From 5b4fe76e48ced1146c26421aa163626a36bc09c9 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Fri, 6 Dec 2013 16:40:56 +0100 Subject: [PATCH] Fix for bug 211, where direct write and read of augmentation was not processed correctly - Fixed TypeNotAvailable issue with end-to-end Openflow Signed-off-by: Tony Tkacik Change-Id: I9797fb4a1b71d456cc9126f98e4f3043e49b5666 --- .../dom/serializer/api/CodecRegistry.java | 5 + .../dom/serializer/api/IdentitityCodec.java | 14 ++ .../dom/serializer/impl/CodecMapping.java | 34 ++- .../serializer/impl/IntermediateMapping.xtend | 12 +- .../impl/LazyGeneratedCodecRegistry.java | 231 ++++++++++++++---- .../RuntimeGeneratedMappingServiceImpl.xtend | 40 ++- .../impl/TransformerGenerator.xtend | 16 +- ...indingIndependentDataServiceConnector.java | 24 +- .../md-sal/sal-binding-dom-it/pom.xml | 9 +- .../test/bugfix/PutAugmentationTest.java | 176 +++++++++++++ .../dom/ChangeOriginatedInDomBrokerTest.java | 3 +- .../sal/restconf/impl/BrokerFacade.xtend | 5 + .../sal/restconf/impl/ControllerContext.xtend | 12 +- 13 files changed, 518 insertions(+), 63 deletions(-) create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentitityCodec.java create mode 100644 opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java 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 a31d3eedd2..b9a4fe87ac 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 @@ -2,6 +2,7 @@ package org.opendaylight.controller.sal.binding.dom.serializer.api; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.Identifier; @@ -14,6 +15,8 @@ import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCode public interface CodecRegistry { InstanceIdentifierCodec getInstanceIdentifierCodec(); + + IdentitityCodec getIdentityCodec(); DataContainerCodec getCodecForDataObject(Class object); @@ -22,6 +25,8 @@ public interface CodecRegistry { > IdentifierCodec getCodecForIdentifier(Class object); > AugmentationCodec getCodecForAugmentation(Class object); + + IdentitityCodec getCodecForIdentity(Class codec); Class getClassForPath(List names); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentitityCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentitityCodec.java new file mode 100644 index 0000000000..0c480f52f1 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentitityCodec.java @@ -0,0 +1,14 @@ +package org.opendaylight.controller.sal.binding.dom.serializer.api; + +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.BindingCodec; +import org.opendaylight.yangtools.yang.common.QName; + +public interface IdentitityCodec extends BindingCodec>{ + + @Override + public QName serialize(Class input); + + @Override + public Class deserialize(QName input); +} 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 172fb05292..fa2d32a138 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 @@ -3,6 +3,7 @@ package org.opendaylight.controller.sal.binding.dom.serializer.impl; import java.lang.reflect.Field; import java.util.Map; +import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentitityCodec; import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec; import org.opendaylight.yangtools.yang.binding.BindingCodec; import org.opendaylight.yangtools.yang.common.QName; @@ -15,6 +16,8 @@ public class CodecMapping { private static final Logger LOG = LoggerFactory.getLogger(CodecMapping.class); public static final String INSTANCE_IDENTIFIER_CODEC = "INSTANCE_IDENTIFIER_CODEC"; + public static final String IDENTITYREF_CODEC = "IDENTITYREF_CODEC"; + public static final String CLASS_TO_CASE_MAP = "CLASS_TO_CASE"; public static final String COMPOSITE_TO_CASE = "COMPOSITE_TO_CASE"; public static final String AUGMENTATION_CODEC = "AUGMENTATION_CODEC"; @@ -27,7 +30,22 @@ public class CodecMapping { instanceIdField.set(null, codec); } } catch (NoSuchFieldException e) { - LOG.debug("Instance identifier codec is not needed for {}",obj.getName(),e); + LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e); + } catch (SecurityException | IllegalAccessException e) { + LOG.error("Instance identifier could not be set for {}",obj.getName(),e); + } + } + + + public static void setIdentityRefCodec(Class obj,IdentitityCodec codec) { + Field instanceIdField; + try { + instanceIdField = obj.getField(IDENTITYREF_CODEC); + if(obj != null) { + instanceIdField.set(null, codec); + } + } catch (NoSuchFieldException e) { + LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e); } catch (SecurityException | IllegalAccessException e) { LOG.error("Instance identifier could not be set for {}",obj.getName(),e); } @@ -71,4 +89,18 @@ public class CodecMapping { LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e); } } + + + public static BindingCodec getAugmentationCodec(Class> dataCodec) { + Field instanceIdField; + try { + instanceIdField = dataCodec.getField(AUGMENTATION_CODEC); + return (BindingCodec) instanceIdField.get(null); + } catch (NoSuchFieldException e) { + LOG.debug("BUG: Augmentation codec is not needed for {}",dataCodec.getName(),e); + } catch (SecurityException | IllegalAccessException e) { + LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e); + } + return null; + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend index d0b114e3c3..04b8674727 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend @@ -13,7 +13,10 @@ class IntermediateMapping { - static def Node toNode(Map map) { + static def Node toNode(Map map) { + if(map instanceof Node) { + return map as Node; + } val nodeMap = map as Map; Preconditions.checkArgument(map.size == 1); val elem = nodeMap.entrySet.iterator.next; @@ -22,10 +25,15 @@ class IntermediateMapping { toNodeImpl(qname, value); } + static def dispatch Node toNodeImpl(QName name, List objects) { val values = new ArrayList>(objects.size); for (obj : objects) { - values.add(toNode(obj as Map)); + if(obj instanceof Node) { + values.add(obj as Node); + } else if(obj instanceof Map) { + values.add(toNode(obj as Map)); + } } return new CompositeNodeTOImpl(name, null, values); } 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 d33272d641..39bd0816f5 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 @@ -1,7 +1,9 @@ package org.opendaylight.controller.sal.binding.dom.serializer.impl; +import java.awt.CompositeContext; import java.lang.ref.WeakReference; import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -12,11 +14,13 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.Set; import java.util.WeakHashMap; +import org.apache.commons.lang3.text.translate.AggregateTranslator; import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec; import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCaseCodec; import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCodec; @@ -24,6 +28,7 @@ import org.opendaylight.controller.sal.binding.dom.serializer.api.CodecRegistry; import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec; 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.IdentitityCodec; 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; @@ -34,6 +39,7 @@ import org.opendaylight.yangtools.concepts.Delegator; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.binding.Augmentable; import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.BindingCodec; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -41,6 +47,7 @@ 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.data.impl.CompositeNodeTOImpl; import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; @@ -61,10 +68,12 @@ import static org.opendaylight.controller.sal.binding.dom.serializer.impl.Interm import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext; import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType; import org.opendaylight.yangtools.sal.binding.model.api.Type; +import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder; import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; +import com.google.common.collect.FluentIterable; import com.google.common.util.concurrent.CycleDetectingLockFactory.WithExplicitOrdering; public class LazyGeneratedCodecRegistry implements // @@ -76,27 +85,31 @@ public class LazyGeneratedCodecRegistry implements // private final static LateMixinCodec NOT_READY_CODEC = new LateMixinCodec(); private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this); + private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec(); private TransformerGenerator generator; // Concrete class to codecs - private Map, DataContainerCodec> containerCodecs = new WeakHashMap<>(); - private Map, IdentifierCodec> identifierCodecs = new WeakHashMap<>(); - private Map, ChoiceCodecImpl> choiceCodecs = new WeakHashMap<>(); - private Map, ChoiceCaseCodecImpl> caseCodecs = new WeakHashMap<>(); - private Map, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>(); - + private static final Map, DataContainerCodec> containerCodecs = new WeakHashMap<>(); + private static final Map, IdentifierCodec> identifierCodecs = new WeakHashMap<>(); + private static final Map, ChoiceCodecImpl> choiceCodecs = new WeakHashMap<>(); + private static final Map, ChoiceCaseCodecImpl> caseCodecs = new WeakHashMap<>(); + private static final Map, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>(); + private static final Map, AugmentationCodec> augmentationCodecs = new WeakHashMap<>(); + private static final Map, QName> identityQNames = new WeakHashMap<>(); + private static final Map qnamesToIdentityMap = new ConcurrentHashMap<>(); /** Binding type to encountered classes mapping **/ @SuppressWarnings("rawtypes") - Map> typeToClass = new ConcurrentHashMap<>(); + private static final Map> typeToClass = new ConcurrentHashMap<>(); @SuppressWarnings("rawtypes") - private ConcurrentMap typeToCaseCodecs = new ConcurrentHashMap<>(); + private static final ConcurrentMap typeToCaseCodecs = new ConcurrentHashMap<>(); private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade(); - Map pathToType = new ConcurrentHashMap<>(); - Map, Type> pathToInstantiatedType = new ConcurrentHashMap<>(); + private static final Map pathToType = new ConcurrentHashMap<>(); + private static final Map, Type> pathToInstantiatedType = new ConcurrentHashMap<>(); + private static final Map typeToQname = new ConcurrentHashMap<>(); private SchemaContext currentSchema; @@ -115,8 +128,56 @@ public class LazyGeneratedCodecRegistry implements // @Override public > AugmentationCodec getCodecForAugmentation(Class object) { - // TODO Auto-generated method stub - return null; + AugmentationCodec codec = null; + @SuppressWarnings("rawtypes") + AugmentationCodec potentialCodec = augmentationCodecs.get(object); + if (potentialCodec != null) { + codec = potentialCodec; + } else + try { + Class, Object>> augmentRawCodec = generator + .augmentationTransformerFor(object); + BindingCodec, Object> rawCodec = augmentRawCodec.newInstance(); + codec = new AugmentationCodecWrapper(rawCodec); + augmentationCodecs.put(augmentRawCodec, codec); + } catch (InstantiationException e) { + LOG.error("Can not instantiate raw augmentation codec {}", object.getSimpleName(), e); + } catch (IllegalAccessException e) { + LOG.debug("BUG: Constructor for {} is not accessible.", object.getSimpleName(), e); + } + Class> objectSupertype = getAugmentableArgumentFrom(object); + if (objectSupertype != null) { + getAugmentableCodec(objectSupertype).addAugmentationCodec(object, codec); + } else { + LOG.warn("Could not find augmentation target for augmentation {}", object); + } + return codec; + } + + private static Class> getAugmentableArgumentFrom( + final Class> augmentation) { + try { + Class> ret = ClassLoaderUtils.withClassLoader(augmentation.getClassLoader(), + new Callable>>() { + @Override + @SuppressWarnings("unchecked") + public Class> call() throws Exception { + for (java.lang.reflect.Type supertype : augmentation.getGenericInterfaces()) { + if (supertype instanceof ParameterizedType + && Augmentation.class.equals(((ParameterizedType) supertype).getRawType())) { + ParameterizedType augmentationGeneric = (ParameterizedType) supertype; + return (Class>) augmentationGeneric + .getActualTypeArguments()[0]; + } + } + return null; + } + }); + return ret; + } catch (Exception e) { + LOG.error("Could not find augmentable for {}", augmentation, e); + return null; + } } @Override @@ -165,7 +226,6 @@ public class LazyGeneratedCodecRegistry implements // return newWrapper; } - @Override @SuppressWarnings("rawtypes") public void bindingClassEncountered(Class cls) { @@ -268,9 +328,21 @@ public class LazyGeneratedCodecRegistry implements // return newWrapper; } + @Override + public IdentitityCodec getIdentityCodec() { + return identityRefCodec; + } + + @Override + public IdentitityCodec getCodecForIdentity(Class codec) { + bindingClassEncountered(codec); + return identityRefCodec; + } + @Override public void onCodecCreated(Class cls) { CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec); + CodecMapping.setIdentityRefCodec(cls, identityRefCodec); } @Override @@ -316,6 +388,10 @@ public class LazyGeneratedCodecRegistry implements // public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) { pathToType.putAll(context.getChildNodes()); + qnamesToIdentityMap.putAll(context.getIdentities()); + for(Entry identity : context.getIdentities().entrySet()) { + typeToQname.put(new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),identity.getKey()); + } captureCases(context.getCases(), schemaContext); } @@ -324,7 +400,6 @@ public class LazyGeneratedCodecRegistry implements // ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode .getValue().getName()); - LOG.info("Case path: {} Type : {}", caseNode.getKey(), caseNode.getValue().getFullyQualifiedName()); pathToType.put(caseNode.getKey(), caseNode.getValue()); ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey()); @@ -371,10 +446,10 @@ public class LazyGeneratedCodecRegistry implements // if (path != null && (type = pathToType.get(path)) != null) { ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName()); ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref); - if(partialCodec.getSchema() == null ) { + if (partialCodec.getSchema() == null) { partialCodec.setSchema(caseNode); } - + Class caseClass = ClassLoaderUtils.tryToLoadClassWithTCCL(type.getFullyQualifiedName()); if (caseClass != null) { getCaseCodecFor(caseClass); @@ -402,7 +477,7 @@ public class LazyGeneratedCodecRegistry implements // } - private AugmentableCompositeCodec getAugmentableCodec(Class dataClass) { + public AugmentableCompositeCodec getAugmentableCodec(Class dataClass) { AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass); if (ret != null) { return ret; @@ -739,7 +814,7 @@ public class LazyGeneratedCodecRegistry implements // private final Class augmentableType; - Map rawAugmentationCodecs = new WeakHashMap<>(); + Map> localAugmentationCodecs = new WeakHashMap<>(); public AugmentableCompositeCodec(Class type) { checkArgument(Augmentable.class.isAssignableFrom(type)); @@ -772,53 +847,33 @@ public class LazyGeneratedCodecRegistry implements // private List serializeImpl(Map input) { List ret = new ArrayList<>(); for (Entry entry : input.entrySet()) { - BindingCodec codec = getRawCodecForAugmentation(entry.getKey()); - List output = (List) codec.serialize(new ValueWithQName(null, entry.getValue())); - ret.addAll(output); + AugmentationCodec codec = getCodecForAugmentation(entry.getKey()); + CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue())); + ret.addAll(node.getChildren()); } return ret; } - private BindingCodec getRawCodecForAugmentation(Class key) { - BindingCodec ret = rawAugmentationCodecs.get(key); - if (ret != null) { - return ret; - } - try { - Class retClass = generator.augmentationTransformerFor(key); - ret = retClass.newInstance(); - rawAugmentationCodecs.put(key, ret); - return ret; - } catch (InstantiationException 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); - } - return null; + public synchronized > void addAugmentationCodec(Class augmentationClass, + AugmentationCodec value) { + localAugmentationCodecs.put(augmentationClass, value); } @Override public Map deserialize(Object input) { Map ret = new HashMap<>(); if (input instanceof CompositeNode) { - for (Entry codec : rawAugmentationCodecs.entrySet()) { - Augmentation value = (Augmentation) codec.getValue().deserialize(input); - if (value != null) { - ret.put(codec.getKey(), value); + List>> codecs = new ArrayList<>(localAugmentationCodecs.entrySet()); + for (Entry> codec : codecs) { + ValueWithQName value = codec.getValue().deserialize((CompositeNode) input); + if (value != null && value.getValue() != null) { + ret.put(codec.getKey(), (Augmentation) value.getValue()); } } } return ret; } - public Map getRawAugmentationCodecs() { - return rawAugmentationCodecs; - } - - public void setRawAugmentationCodecs(Map rawAugmentationCodecs) { - this.rawAugmentationCodecs = rawAugmentationCodecs; - } - public Class getAugmentableType() { return augmentableType; } @@ -847,4 +902,82 @@ public class LazyGeneratedCodecRegistry implements // return getDelegate().serialize(input); } } + + private static class AugmentationCodecWrapper> implements AugmentationCodec, + Delegator { + + private BindingCodec delegate; + + public AugmentationCodecWrapper(BindingCodec, Object> rawCodec) { + this.delegate = rawCodec; + } + + @Override + public BindingCodec getDelegate() { + return delegate; + } + + @Override + public CompositeNode serialize(ValueWithQName input) { + @SuppressWarnings("unchecked") + List> rawValues = (List>) getDelegate().serialize(input); + List> serialized = new ArrayList<>(rawValues.size()); + for (Map val : rawValues) { + serialized.add(toNode(val)); + } + return new CompositeNodeTOImpl(input.getQname(), null, serialized); + } + + @Override + @SuppressWarnings("unchecked") + public ValueWithQName deserialize(Node input) { + Object rawCodecValue = getDelegate().deserialize((Map) input); + return new ValueWithQName(input.getNodeType(), (T) rawCodecValue); + } + } + + private class IdentityCompositeCodec implements IdentitityCodec { + + @Override + public Object deserialize(Object input) { + checkArgument(input instanceof QName); + return deserialize((QName) input); + } + + @Override + public Class deserialize(QName input) { + Type type = qnamesToIdentityMap.get(input); + if(type == null) { + return null; + } + ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName()); + WeakReference softref = typeToClass.get(typeref); + if(softref == null) { + return null; + } + return softref.get(); + } + + @Override + public QName serialize(Class input) { + checkArgument(BaseIdentity.class.isAssignableFrom(input)); + bindingClassEncountered(input); + QName qname = identityQNames.get(input); + if(qname != null) { + return qname; + } + ConcreteType typeref = Types.typeForClass(input); + qname = typeToQname.get(typeref); + if(qname != null) { + identityQNames.put(input, qname); + } + return qname; + } + + @Override + public Object serialize(Object input) { + checkArgument(input instanceof Class); + return serialize((Class) input); + } + } } \ No newline at end of file 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 cb25f4da8b..13975cad4c 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 @@ -37,6 +37,12 @@ import org.opendaylight.controller.sal.binding.impl.connect.dom.DeserializationE import java.util.concurrent.Callable import org.opendaylight.yangtools.yang.binding.Augmentation import org.opendaylight.controller.sal.binding.impl.util.YangSchemaUtils +import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates +import java.util.ArrayList +import org.opendaylight.yangtools.yang.data.api.Node +import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable { @@ -112,9 +118,21 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer override Entry toDataDom( Entry, DataObject> entry) { + + try { val key = toDataDom(entry.key) - val data = toCompositeNodeImpl(entry.value); + var CompositeNode data; + if(Augmentation.isAssignableFrom(entry.key.targetType)) { + data = toCompositeNodeImpl(key,entry.value); + } else { + data = toCompositeNodeImpl(entry.value); + } return new SimpleEntry(key, data); + + } catch (Exception e) { + LOG.error("Error during serialization for {}.", entry.key,e); + throw e; + } } private def CompositeNode toCompositeNodeImpl(DataObject object) { @@ -124,6 +142,26 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer val ret = codec.serialize(new ValueWithQName(null, object)); return ret as CompositeNode; } + + + private def CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) { + + //val cls = object.implementedInterface; + //waitForSchema(cls); + val last = identifier.path.last; + val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec; + val ret = codec.serialize(new ValueWithQName(last.nodeType, object)); + if(last instanceof NodeIdentifierWithPredicates) { + val predicates = last as NodeIdentifierWithPredicates; + val newNodes = new ArrayList>(predicates.keyValues.size); + for(predicate : predicates.keyValues.entrySet) { + newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value)); + } + newNodes.addAll(ret.children); + return new CompositeNodeTOImpl(last.nodeType,null,newNodes); + } + return ret as CompositeNode; + } private def void waitForSchema(Class class1) { if(Augmentation.isAssignableFrom(class1)) { 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 0316614aa1..b2d25af885 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 @@ -91,6 +91,8 @@ class TransformerGenerator { @Property var GeneratorListener listener; + + public static val CLASS_TYPE = Types.typeForClass(Class); public new(ClassPool pool) { classPool = pool; @@ -269,6 +271,7 @@ class TransformerGenerator { val ctCls = createClass(inputType.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) staticQNameField(node.QName); implementsType(BINDING_CODEC) method(Object, "toDomStatic", QName, Object) [ @@ -351,6 +354,7 @@ class TransformerGenerator { staticQNameField(node.QName); staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) staticField(it, AUGMENTATION_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) method(Object, "toDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC body = ''' @@ -409,6 +413,7 @@ class TransformerGenerator { //staticField(Map,"AUGMENTATION_SERIALIZERS"); staticQNameField(node.QName); staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) staticField(it, AUGMENTATION_CODEC, BindingCodec) implementsType(BINDING_CODEC) method(Object, "toDomStatic", QName, Object) [ @@ -459,6 +464,7 @@ class TransformerGenerator { staticQNameField(node.augmentationQName); staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) staticField(it, AUGMENTATION_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) implementsType(BINDING_CODEC) method(Object, "toDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC @@ -466,7 +472,7 @@ class TransformerGenerator { { //System.out.println("Qname " + $1); //System.out.println("Value " + $2); - «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName()); + «QName.name» _resultName = «QName.name».create(QNAME,QNAME.getLocalName()); java.util.List _childNodes = new java.util.ArrayList(); «type.resolvedName» value = («type.resolvedName») $2; «FOR child : node.childNodes» @@ -540,6 +546,7 @@ class TransformerGenerator { //staticField(Map,"AUGMENTATION_SERIALIZERS"); //staticQNameField(inputType); staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) staticField(it, CLASS_TO_CASE_MAP, Map) staticField(it, COMPOSITE_TO_CASE, Map) //staticField(it,QNAME_TO_CASE_MAP,BindingCodec) @@ -828,6 +835,7 @@ class TransformerGenerator { if (hasYangBinding) { implementsType(BINDING_CODEC) staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) implementsType(BindingDeserializer.asCtClass) } method(Object, "toDomValue", Object) [ @@ -1020,10 +1028,10 @@ class TransformerGenerator { private def dispatch String deserializeValue(Type type, String domParameter) { if (INSTANCE_IDENTIFIER.equals(type)) { - return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)''' + } else if (CLASS_TYPE.equals(type)) { + return '''(«Class.name») «IDENTITYREF_CODEC».deserialize(«domParameter»)''' } - return '''(«type.resolvedName») «domParameter»''' } @@ -1192,6 +1200,8 @@ class TransformerGenerator { private def dispatch serializeValue(Type signature, String property) { if (INSTANCE_IDENTIFIER == signature) { return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)''' + }else if (CLASS_TYPE.equals(signature)) { + return '''(«QName.resolvedName») «IDENTITYREF_CODEC».serialize(«property»)''' } return '''«property»'''; } 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 5f3189f7d2..9eff29f8cc 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 @@ -22,6 +22,8 @@ import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.binding.Augmentable; +import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcError; @@ -61,8 +63,22 @@ public class BindingIndependentDataServiceConnector implements // public DataObject readOperationalData(InstanceIdentifier path) { try { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); + + CompositeNode result = biDataService.readOperationalData(biPath); + Class targetType = path.getTargetType(); + + if(Augmentation.class.isAssignableFrom(targetType)) { + path = mappingService.fromDataDom(biPath); + Class> augmentType = (Class>) targetType; + DataObject parentTo = mappingService.dataObjectFromDataDom(path, result); + if(parentTo instanceof Augmentable) { + return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType); + } + + } return mappingService.dataObjectFromDataDom(path, result); + } catch (DeserializationException e) { throw new IllegalStateException(e); } @@ -116,7 +132,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: {}.", entry.getKey(), e); } } for (Entry entry : source @@ -127,7 +143,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: {}.", entry.getKey(), e); } } for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) { @@ -136,7 +152,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: {}.", entry, e); } } for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) { @@ -145,7 +161,7 @@ public class BindingIndependentDataServiceConnector implements // InstanceIdentifier baEntry = mappingService.fromDataDom(entry); target.removeOperationalData(baEntry); } catch (DeserializationException e) { - LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry, e); + LOG.error("Ommiting from BA transaction: {}.", entry, e); } } return target; diff --git a/opendaylight/md-sal/sal-binding-dom-it/pom.xml b/opendaylight/md-sal/sal-binding-dom-it/pom.xml index 9a143d3f00..6525fa078e 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-dom-it/pom.xml @@ -49,7 +49,7 @@ - + org.opendaylight.controller sal-binding-broker-impl 1.0-SNAPSHOT @@ -78,5 +78,12 @@ junit junit + + + org.slf4j + slf4j-simple + test + 1.7.2 + diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java new file mode 100644 index 0000000000..96d0361b1d --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java @@ -0,0 +1,176 @@ +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; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; +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.binding.InstanceIdentifier.InstanceIdentifierBuilder; +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 PutAugmentationTest extends AbstractDataServiceTest implements DataChangeListener { + + private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); + private static final String NODE_ID = "openflow:1"; + + private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID)); + + private static final Map NODE_KEY_BI = Collections. singletonMap(NODE_ID_QNAME, + NODE_ID); + + private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // + .toInstance(); + + + 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; + + + + /** + * Test for Bug 148 + * + * @throws Exception + */ + @Test + public void putNodeAndAugmentation() throws Exception { + + baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this); + + NodeBuilder nodeBuilder = new NodeBuilder(); + nodeBuilder.setId(new NodeId(NODE_ID)); + nodeBuilder.setKey(NODE_KEY); + DataModificationTransaction baseTransaction = baDataService.beginTransaction(); + baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build()); + RpcResult result = baseTransaction.commit().get(); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + assertNotNull(receivedChangeEvent); + Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); + assertNotNull(node); + assertEquals(NODE_KEY, node.getKey()); + + FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder(); + fnub.setHardware("Hardware Foo"); + fnub.setManufacturer("Manufacturer Foo"); + fnub.setSerialNumber("Serial Foo"); + fnub.setDescription("Description Foo"); + fnub.setSoftware("JUnit emulated"); + FlowCapableNode fnu = fnub.build(); + InstanceIdentifier augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance(); + DataModificationTransaction augmentedTransaction = baDataService.beginTransaction(); + augmentedTransaction.putOperationalData(augmentIdentifier, fnu); + + result = augmentedTransaction.commit().get(); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + + + Node augmentedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); + assertNotNull(node); + assertEquals(NODE_KEY, augmentedNode.getKey()); + System.out.println("Before assertion"); + assertNotNull(augmentedNode.getAugmentation(FlowCapableNode.class)); + FlowCapableNode readedAugmentation = augmentedNode.getAugmentation(FlowCapableNode.class); + assertEquals(fnu.getDescription(), readedAugmentation.getDescription()); + assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); + testNodeRemove(); + } + + + private void testNodeRemove() throws Exception { + DataModificationTransaction transaction = baDataService.beginTransaction(); + transaction.removeOperationalData(NODE_INSTANCE_ID_BA); + RpcResult result = transaction.commit().get(); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + + Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); + assertNull(node); + } + + private void verifyNodes(Nodes nodes,Node original) { + assertNotNull(nodes); + assertNotNull(nodes.getNode()); + assertEquals(1, nodes.getNode().size()); + Node readedNode = nodes.getNode().get(0); + assertEquals(original.getId(), readedNode.getId()); + assertEquals(original.getKey(), readedNode.getKey()); + + FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class); + FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class); + assertNotNull(fnu); + assertEquals(fnu.getDescription(), readedAugment.getDescription()); + assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber()); + + } + + private void assertBindingIndependentVersion( + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) { + CompositeNode node = biDataService.readOperationalData(nodeId); + assertNotNull(node); + } + + private Nodes checkForNodes() { + return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA); + } + + @Override + public void onDataChanged(DataChangeEvent, DataObject> change) { + receivedChangeEvent = change; + } + +} diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java index 7fe5f0c5be..7111501b53 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java @@ -116,6 +116,7 @@ public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest { @Test public void simpleModifyOperation() throws Exception { + assertNull(biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI)); registerCommitHandler(); @@ -123,7 +124,7 @@ public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest { DataModificationTransaction biTransaction = biDataService.beginTransaction(); biTransaction.putConfigurationData(FLOW_INSTANCE_ID_BI, domflow); RpcResult biResult = biTransaction.commit().get(); - + assertEquals(TransactionStatus.COMMITED, biResult.getResult()); assertNotNull(modificationCapture); Flow flow = (Flow) modificationCapture.getCreatedConfigurationData().get(FLOW_INSTANCE_ID_BA); assertNotNull(flow); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend index 1b0fda41ca..df6b58c897 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend @@ -9,9 +9,12 @@ import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.common.RpcResult import org.opendaylight.yangtools.yang.data.api.CompositeNode import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier +import org.slf4j.LoggerFactory class BrokerFacade implements DataReader { + + val static LOG = LoggerFactory.getLogger(BrokerFacade) val static BrokerFacade INSTANCE = new BrokerFacade @Property @@ -38,11 +41,13 @@ class BrokerFacade implements DataReader { override readConfigurationData(InstanceIdentifier path) { checkPreconditions + LOG.info("Read Configuration via Restconf: {}",path) return dataService.readConfigurationData(path); } override readOperationalData(InstanceIdentifier path) { checkPreconditions + LOG.info("Read Operational via Restconf: {}",path) return dataService.readOperationalData(path); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend index 602e8b9242..fed56fe297 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend @@ -33,6 +33,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil import static com.google.common.base.Preconditions.* import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec +import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition class ControllerContext implements SchemaServiceListener { @@ -291,7 +292,16 @@ class ControllerContext implements SchemaServiceListener { checkArgument(node instanceof LeafSchemaNode); val urlDecoded = URLDecoder.decode(uriValue); val typedef = (node as LeafSchemaNode).type; - val decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded) + var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded) + if(decoded == null) { + var baseType = typedef + while (baseType.baseType != null) { + baseType = baseType.baseType; + } + if(baseType instanceof IdentityrefTypeDefinition) { + decoded = toQName(urlDecoded) + } + } map.put(node.QName, decoded); } -- 2.36.6