From: Tony Tkacik Date: Wed, 9 Jul 2014 15:42:59 +0000 (+0200) Subject: Bug 1284: Fixed serialization of Augment Instance Identifier X-Git-Tag: release/helium~493 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=c95dcd50df1b77775ad14d811b178c5574a67f48 Bug 1284: Fixed serialization of Augment Instance Identifier Instance Identifier pointing to Augmentation, which pointed to augmentation with leafs only, was not properly serialized to DOM Instance Identifier and this caused subscription for parent node. Instance Identifier Codec was updated to detect this case and use different algorithm to serialize last argument. Change-Id: Ie47ec7a5ebc86e10a7e1b3ddbc8921bf089466b2 Signed-off-by: Tony Tkacik --- diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index f7256c62f6..2f3410dedc 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -108,6 +108,11 @@ ietf-topology-l3-unicast-igp test + + org.opendaylight.controller + sal-test-model + ${project.version} + org.slf4j slf4j-simple diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java index 8723fdf82a..d275c838f2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java @@ -8,12 +8,11 @@ package org.opendaylight.controller.md.sal.binding.impl; import java.lang.reflect.Method; -import java.lang.reflect.Type; import java.util.AbstractMap.SimpleEntry; +import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; import java.util.Map.Entry; +import java.util.Set; import javax.annotation.Nullable; @@ -21,13 +20,13 @@ import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizat import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.BindingMapping; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item; +import org.opendaylight.yangtools.yang.binding.YangModuleInfo; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; -import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; @@ -40,6 +39,9 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; +import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.slf4j.Logger; @@ -48,7 +50,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.base.Supplier; +import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; @@ -99,8 +101,8 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { if (child instanceof AugmentationNode) { ImmutableList childArgs = ImmutableList. builder() .addAll(normalizedEntry.getKey().getPathArguments()).add(child.getIdentifier()).build(); - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create( - childArgs); + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier + .create(childArgs); return toDOMEntry(childPath, child); } } @@ -121,7 +123,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { */ public Optional> toBinding( final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) - throws DeserializationException { + throws DeserializationException { PathArgument lastArgument = Iterables.getLast(normalized.getPathArguments()); // Used instance-identifier codec do not support serialization of last @@ -138,7 +140,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { private Optional> toBindingAugmented( final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) - throws DeserializationException { + throws DeserializationException { Optional> potential = toBindingImpl(normalized); // Shorthand check, if codec already supports deserialization // of AugmentationIdentifier we will return @@ -188,7 +190,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { private Optional> toBindingImpl( final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) - throws DeserializationException { + throws DeserializationException { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath; try { @@ -207,10 +209,10 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { private boolean isNotRepresentable(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) throws DataNormalizationException { DataNormalizationOperation op = findNormalizationOperation(normalized); - if( op.isMixin() && op.getIdentifier() instanceof NodeIdentifier) { + if (op.isMixin() && op.getIdentifier() instanceof NodeIdentifier) { return true; } - if(op.isLeaf()) { + if (op.isLeaf()) { return true; } return false; @@ -218,7 +220,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { private DataNormalizationOperation findNormalizationOperation( final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) - throws DataNormalizationException { + throws DataNormalizationException { DataNormalizationOperation current = legacyToNormalized.getRootOperation(); for (PathArgument arg : normalized.getPathArguments()) { current = current.getChild(arg); @@ -234,10 +236,9 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { } private static final Entry> toDOMEntry( - final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier key, - final NormalizedNode value) { - return new SimpleEntry>( - key, value); + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier key, final NormalizedNode value) { + return new SimpleEntry>(key, + value); } public DataObject toBinding(final InstanceIdentifier path, final NormalizedNode normalizedNode) @@ -263,7 +264,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { public Optional, DataObject>> toBinding( final Entry> normalized) - throws DeserializationException { + throws DeserializationException { Optional> potentialPath = toBinding(normalized.getKey()); if (potentialPath.isPresent()) { InstanceIdentifier bindingPath = potentialPath.get(); @@ -290,27 +291,155 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { if (isAugmentationIdentifier(processed)) { return processed; } - // Here we employ small trick - DataNormalizer injects augmentation - // identifier if child is - // also part of the path (since using a child we can safely identify - // augmentation) - // so, we scan augmentation for children add it to path - // and use original algorithm, then shorten it to last augmentation - for (@SuppressWarnings("rawtypes") - Class augChild : getAugmentationChildren(augPath.getTargetType())) { + Optional additionalSerialized; + additionalSerialized = toNormalizedAugmentedUsingChildContainers(augPath, processed); + + if (additionalSerialized.isPresent()) { + return additionalSerialized.get(); + } + additionalSerialized = toNormalizedAugmentedUsingChildLeafs(augPath, processed); + if (additionalSerialized.isPresent()) { + return additionalSerialized.get(); + } + throw new IllegalStateException("Unabled to construct augmentation identfier for " + augPath); + } + + /** + * Tries to find correct augmentation identifier using children leafs + * + * This method uses normalized Instance Identifier of parent node to fetch + * schema and {@link BindingReflections#getModuleInfo(Class)} to learn about + * augmentation namespace, specificly, in which module it was defined. + * + * Then it uses it to filter all available augmentations for parent by + * module. After that it walks augmentations in particular module and + * pick-up first which at least one leaf name matches supplied augmentation. + * We could do this safely since YANG explicitly states that no any existing + * augmentations must differ in leaf fully qualified names. + * + * + * @param augPath + * Binding Aware Path which ends with augment + * @param parentPath + * Processed path + * @return + */ + private Optional toNormalizedAugmentedUsingChildLeafs( + final InstanceIdentifier augPath, + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier parentPath) { + try { + DataNormalizationOperation parentOp = legacyToNormalized.getOperation(parentPath); + if(!parentOp.getDataSchemaNode().isPresent()) { + return Optional.absent(); + } + DataSchemaNode parentSchema = parentOp.getDataSchemaNode().get(); + if (parentSchema instanceof AugmentationTarget) { + Set augmentations = ((AugmentationTarget) parentSchema).getAvailableAugmentations(); + LOG.info("Augmentations for {}, {}", augPath, augmentations); + Optional schema = findAugmentation(augPath.getTargetType(), augmentations); + if (schema.isPresent()) { + AugmentationIdentifier augmentationIdentifier = DataNormalizationOperation + .augmentationIdentifierFrom(schema.get()); + return Optional.of(parentPath.node(augmentationIdentifier)); + } + } + } catch (DataNormalizationException e) { + throw new IllegalArgumentException(e); + } + return Optional.absent(); + } + + /** + * Creates instance identifier for augmentation child, tries to serialize it + * Instance Identifier is then shortened to last augmentation. + * + * This is for situations, where underlying codec is implementing hydrogen + * style DOM APIs (which did not supported {@link AugmentationIdentifier}.) + * + * @param augPath + * @param parentPath + * Path to parent node + * @return + */ + @SuppressWarnings("rawtypes") + private Optional toNormalizedAugmentedUsingChildContainers( + final InstanceIdentifier augPath, + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier parentPath) { + for (Class augChild : BindingReflections.getChildrenClasses(augPath.getTargetType())) { @SuppressWarnings("unchecked") InstanceIdentifier childPath = augPath.child(augChild); org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = toNormalizedImpl(childPath); - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potentialDiscovered = shortenToLastAugmentation(normalized); + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potentialDiscovered = shortenToLastAugmentation( + normalized, parentPath); if (potentialDiscovered != null) { - return potentialDiscovered; + return Optional.of(potentialDiscovered); + } + } + return Optional.absent(); + } + + private Optional findAugmentation(final Class targetType, + final Set augmentations) { + YangModuleInfo moduleInfo; + try { + moduleInfo = BindingReflections.getModuleInfo(targetType); + } catch (Exception e) { + throw new IllegalStateException(e); + } + Iterable filtered = filteredByModuleInfo(augmentations, + BindingReflections.getModuleQName(moduleInfo).getModule()); + filtered.toString(); + Set targetTypeGetters = getYangModeledGetters(targetType); + for (AugmentationSchema schema : filtered) { + for (DataSchemaNode child : schema.getChildNodes()) { + String getterName = "get" + BindingMapping.getClassName(child.getQName()); + if (targetTypeGetters.contains(getterName)) { + return Optional.of(schema); + } } } - return processed; + return Optional.absent(); + } + + private static Iterable filteredByModuleInfo(final Iterable augmentations, + final QNameModule module) { + return Iterables.filter(augmentations, new Predicate() { + @Override + public boolean apply(final AugmentationSchema schema) { + final Set childNodes = schema.getChildNodes(); + return !schema.getChildNodes().isEmpty() + && module.equals(Iterables.get(childNodes, 0).getQName().getModule()); + } + }); + } + + public static final Set getYangModeledGetters(final Class targetType) { + HashSet ret = new HashSet(); + for (Method method : targetType.getMethods()) { + if (isYangModeledGetter(method)) { + ret.add(method.getName()); + } + } + return ret; + } + + /** + * + * Returns true if supplied method represent getter for YANG modeled value + * + * @param method + * Method to be tested + * @return true if method represent getter for YANG Modeled value. + */ + private static final boolean isYangModeledGetter(final Method method) { + return !method.getName().equals("getClass") && !method.getName().equals("getImplementedInterface") + && method.getName().startsWith("get") && method.getParameterTypes().length == 0; } private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier shortenToLastAugmentation( - final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) { + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized, + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier parentPath) { + int parentSize = Iterables.size(parentPath.getPathArguments()); int position = 0; int foundPosition = -1; for (PathArgument arg : normalized.getPathArguments()) { @@ -319,7 +448,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { foundPosition = position; } } - if (foundPosition > 0) { + if (foundPosition > 0 && foundPosition > parentSize) { Iterable shortened = Iterables.limit(normalized.getPathArguments(), foundPosition); return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create(shortened); } @@ -348,62 +477,6 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { return normalized; } - @SuppressWarnings("unchecked") - private Iterable> getAugmentationChildren(final Class targetType) { - List> ret = new LinkedList<>(); - for (Method method : targetType.getMethods()) { - Class entity = getYangModeledType(method); - if (entity != null) { - ret.add((Class) entity); - } - } - return ret; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private Class getYangModeledType(final Method method) { - if (method.getName().equals("getClass") || !method.getName().startsWith("get") - || method.getParameterTypes().length > 0) { - return null; - } - - Class returnType = method.getReturnType(); - if (DataContainer.class.isAssignableFrom(returnType)) { - return (Class) returnType; - } else if (List.class.isAssignableFrom(returnType)) { - try { - return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(), - new Supplier() { - @Override - public Class get() { - Type listResult = ClassLoaderUtils.getFirstGenericParameter(method - .getGenericReturnType()); - if (listResult instanceof Class - && DataObject.class.isAssignableFrom((Class) listResult)) { - return (Class) listResult; - } - return null; - } - - }); - } catch (Exception e) { - LOG.debug("Could not get YANG modeled entity for {}", method, e); - return null; - } - - } - return null; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static InstanceIdentifier toWildcarded(final InstanceIdentifier orig) { - List wildArgs = new LinkedList<>(); - for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : orig.getPathArguments()) { - wildArgs.add(new Item(arg.getType())); - } - return InstanceIdentifier.create(wildArgs); - } - private static boolean isAugmentation(final Class type) { return Augmentation.class.isAssignableFrom(type); } @@ -418,26 +491,26 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { private static int getAugmentationCount(final InstanceIdentifier potential) { int count = 0; - for(org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) { - if(isAugmentation(arg.getType())) { + for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) { + if (isAugmentation(arg.getType())) { count++; } - } return count; } private static int getAugmentationCount(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potential) { int count = 0; - for(PathArgument arg : potential.getPathArguments()) { - if(arg instanceof AugmentationIdentifier) { + for (PathArgument arg : potential.getPathArguments()) { + if (arg instanceof AugmentationIdentifier) { count++; } } return count; } - public Function>, Optional> deserializeFunction(final InstanceIdentifier path) { + public Function>, Optional> deserializeFunction( + final InstanceIdentifier path) { return new DeserializeFunction(this, path); } @@ -475,7 +548,8 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { /** * Returns an default object according to YANG schema for supplied path. * - * @param path DOM Path + * @param path + * DOM Path * @return Node with defaults set on. */ public NormalizedNode getDefaultNodeFor(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/AbstractSchemaAwareTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/AbstractSchemaAwareTest.java new file mode 100644 index 0000000000..61eb42648f --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/AbstractSchemaAwareTest.java @@ -0,0 +1,32 @@ +package org.opendaylight.controller.md.sal.binding.impl.test; + +import org.junit.Before; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.yangtools.yang.binding.YangModuleInfo; +import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public abstract class AbstractSchemaAwareTest { + + private Iterable moduleInfos; + private SchemaContext schemaContext; + + + protected Iterable getModuleInfos() { + return BindingReflections.loadModuleInfos(); + } + + + @Before + public final void setup() { + moduleInfos = getModuleInfos(); + ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create(); + moduleContext.addModuleInfos(moduleInfos); + schemaContext = moduleContext.tryToCreateSchemaContext().get(); + setupWithSchema(schemaContext); + } + + + protected abstract void setupWithSchema(SchemaContext context); + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java new file mode 100644 index 0000000000..5ad474a9a3 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java @@ -0,0 +1,59 @@ +package org.opendaylight.controller.md.sal.binding.impl.test; + +import static org.junit.Assert.assertTrue; +import javassist.ClassPool; + +import org.junit.Test; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey; +import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public class BindingNormalizedCodecTest extends AbstractSchemaAwareTest { + + private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo"); + private static final InstanceIdentifier BA_TOP_LEVEL_LIST = InstanceIdentifier + .builder(Top.class).child(TopLevelList.class, TOP_FOO_KEY).toInstance(); + private static final InstanceIdentifier BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class); + private static final InstanceIdentifier BA_TREE_LEAF_ONLY_USES = BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyUsesAugment.class); + private static final InstanceIdentifier BA_TREE_COMPLEX_USES = BA_TOP_LEVEL_LIST.augmentation(TreeComplexUsesAugment.class); + private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value"); + + + private RuntimeGeneratedMappingServiceImpl mappingService; + private BindingToNormalizedNodeCodec codec; + + @Override + protected void setupWithSchema(final SchemaContext context) { + mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault()); + codec = new BindingToNormalizedNodeCodec(mappingService); + mappingService.onGlobalContextUpdated(context); + codec.onGlobalContextUpdated(context); + }; + + @Test + public void testComplexAugmentationSerialization() { + + PathArgument lastArg = codec.toNormalized(BA_TREE_COMPLEX_USES).getLastPathArgument(); + assertTrue(lastArg instanceof AugmentationIdentifier); + } + + + @Test + public void testLeafOnlyAugmentationSerialization() { + + PathArgument leafOnlyLastArg = codec.toNormalized(BA_TREE_LEAF_ONLY).getLastPathArgument(); + assertTrue(leafOnlyLastArg instanceof AugmentationIdentifier); + assertTrue(((AugmentationIdentifier) leafOnlyLastArg).getPossibleChildNames().contains(SIMPLE_VALUE_QNAME)); + } + +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationOperation.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationOperation.java index 2b9694bed7..6176977104 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationOperation.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationOperation.java @@ -10,11 +10,6 @@ package org.opendaylight.controller.md.sal.common.impl.util.compat; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import com.google.common.base.Optional; -import com.google.common.collect.FluentIterable; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; - import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -52,19 +47,31 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; + +import com.google.common.base.Optional; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; public abstract class DataNormalizationOperation implements Identifiable { private final T identifier; + private final Optional dataSchemaNode; @Override public T getIdentifier() { return identifier; }; - protected DataNormalizationOperation(final T identifier) { + protected DataNormalizationOperation(final T identifier, final SchemaNode schema) { super(); this.identifier = identifier; + if(schema instanceof DataSchemaNode) { + this.dataSchemaNode = Optional.of((DataSchemaNode) schema); + } else { + this.dataSchemaNode = Optional.absent(); + } } public boolean isMixin() { @@ -88,10 +95,15 @@ public abstract class DataNormalizationOperation impleme public abstract boolean isLeaf(); + public Optional getDataSchemaNode() { + // FIXME + return dataSchemaNode; + } + private static abstract class SimpleTypeNormalization extends DataNormalizationOperation { - protected SimpleTypeNormalization(final T identifier) { - super(identifier); + protected SimpleTypeNormalization(final T identifier, final DataSchemaNode potential) { + super(identifier,potential); } @Override @@ -127,8 +139,8 @@ public abstract class DataNormalizationOperation impleme private static final class LeafNormalization extends SimpleTypeNormalization { - protected LeafNormalization(final NodeIdentifier identifier) { - super(identifier); + protected LeafNormalization(final LeafSchemaNode potential) { + super(new NodeIdentifier(potential.getQName()),potential); } @Override @@ -141,7 +153,7 @@ public abstract class DataNormalizationOperation impleme private static final class LeafListEntryNormalization extends SimpleTypeNormalization { public LeafListEntryNormalization(final LeafListSchemaNode potential) { - super(new NodeWithValue(potential.getQName(), null)); + super(new NodeWithValue(potential.getQName(), null),potential); } @Override @@ -160,8 +172,8 @@ public abstract class DataNormalizationOperation impleme private static abstract class CompositeNodeNormalizationOperation extends DataNormalizationOperation { - protected CompositeNodeNormalizationOperation(final T identifier) { - super(identifier); + protected CompositeNodeNormalizationOperation(final T identifier, final DataSchemaNode schema) { + super(identifier,schema); } @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -226,8 +238,8 @@ public abstract class DataNormalizationOperation impleme private final Map> byQName; private final Map> byArg; - protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) { - super(identifier); + protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema, final DataSchemaNode node) { + super(identifier,node); this.schema = schema; this.byArg = new ConcurrentHashMap<>(); this.byQName = new ConcurrentHashMap<>(); @@ -283,7 +295,7 @@ public abstract class DataNormalizationOperation impleme private final List keyDefinition; protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) { - super(identifier, schema); + super(identifier, schema,schema); keyDefinition = schema.getKeyDefinition(); } @@ -324,7 +336,7 @@ public abstract class DataNormalizationOperation impleme private static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation { protected UnkeyedListItemNormalization(final ListSchemaNode schema) { - super(new NodeIdentifier(schema.getQName()), schema); + super(new NodeIdentifier(schema.getQName()), schema,schema); } @Override @@ -342,7 +354,7 @@ public abstract class DataNormalizationOperation impleme private static final class ContainerNormalization extends DataContainerNormalizationOperation { protected ContainerNormalization(final ContainerSchemaNode schema) { - super(new NodeIdentifier(schema.getQName()), schema); + super(new NodeIdentifier(schema.getQName()),schema, schema); } @Override @@ -360,8 +372,8 @@ public abstract class DataNormalizationOperation impleme private static abstract class MixinNormalizationOp extends CompositeNodeNormalizationOperation { - protected MixinNormalizationOp(final T identifier) { - super(identifier); + protected MixinNormalizationOp(final T identifier, final DataSchemaNode schema) { + super(identifier,schema); } @Override @@ -395,7 +407,7 @@ public abstract class DataNormalizationOperation impleme private final DataNormalizationOperation innerOp; public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) { - super(new NodeIdentifier(potential.getQName())); + super(new NodeIdentifier(potential.getQName()),potential); innerOp = new LeafListEntryNormalization(potential); } @@ -430,7 +442,7 @@ public abstract class DataNormalizationOperation impleme public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) { //super(); - super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema)); + super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema),null); } @Override @@ -479,7 +491,7 @@ public abstract class DataNormalizationOperation impleme private final ListItemNormalization innerNode; public UnorderedMapMixinNormalization(final ListSchemaNode list) { - super(new NodeIdentifier(list.getQName())); + super(new NodeIdentifier(list.getQName()),list); this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(), Collections. emptyMap()), list); } @@ -519,7 +531,7 @@ public abstract class DataNormalizationOperation impleme private final UnkeyedListItemNormalization innerNode; public UnkeyedListMixinNormalization(final ListSchemaNode list) { - super(new NodeIdentifier(list.getQName())); + super(new NodeIdentifier(list.getQName()),list); this.innerNode = new UnkeyedListItemNormalization(list); } @@ -577,7 +589,7 @@ public abstract class DataNormalizationOperation impleme private final ImmutableMap> byArg; protected ChoiceNodeNormalization(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) { - super(new NodeIdentifier(schema.getQName())); + super(new NodeIdentifier(schema.getQName()),schema); ImmutableMap.Builder> byQNameBuilder = ImmutableMap.builder(); ImmutableMap.Builder> byArgBuilder = ImmutableMap.builder(); @@ -617,8 +629,8 @@ public abstract class DataNormalizationOperation impleme private static class AnyXmlNormalization extends DataNormalizationOperation { - protected AnyXmlNormalization( final NodeIdentifier identifier ) { - super( identifier ); + protected AnyXmlNormalization( final AnyXmlSchemaNode schema) { + super( new NodeIdentifier(schema.getQName()), schema); } @Override @@ -746,13 +758,13 @@ public abstract class DataNormalizationOperation impleme return fromListSchemaNode((ListSchemaNode) potential); } else if (potential instanceof LeafSchemaNode) { - return new LeafNormalization(new NodeIdentifier(potential.getQName())); + return new LeafNormalization((LeafSchemaNode) potential); } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) { return new ChoiceNodeNormalization((org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential); } else if (potential instanceof LeafListSchemaNode) { return fromLeafListSchemaNode((LeafListSchemaNode) potential); } else if (potential instanceof AnyXmlSchemaNode) { - return new AnyXmlNormalization( new NodeIdentifier(potential.getQName() ) ); + return new AnyXmlNormalization( (AnyXmlSchemaNode) potential); } return null; } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizer.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizer.java index 113d3dc9f7..e2a960a67a 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizer.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizer.java @@ -9,12 +9,6 @@ package org.opendaylight.controller.md.sal.common.impl.util.compat; import static com.google.common.base.Preconditions.checkArgument; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicates; -import com.google.common.collect.FluentIterable; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; - import java.util.AbstractMap; import java.util.ArrayList; import java.util.Iterator; @@ -38,6 +32,12 @@ import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl; import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicates; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + public class DataNormalizer { private final DataNormalizationOperation operation; @@ -72,6 +72,16 @@ public class DataNormalizer { return InstanceIdentifier.create(normalizedArgs.build()); } + public DataNormalizationOperation getOperation(final InstanceIdentifier legacy) throws DataNormalizationException { + DataNormalizationOperation currentOp = operation; + Iterator arguments = legacy.getPathArguments().iterator(); + + while (arguments.hasNext()) { + currentOp = currentOp.getChild(arguments.next()); + } + return currentOp; + } + public Map.Entry> toNormalized( final Map.Entry legacy) { return toNormalized(legacy.getKey(), legacy.getValue()); @@ -120,7 +130,7 @@ public class DataNormalizer { DataNormalizationOperation currentOp = operation; for (PathArgument normalizedArg : normalized.getPathArguments()) { currentOp = currentOp.getChild(normalizedArg); - if(!currentOp.isMixin()) { + if (!currentOp.isMixin()) { legacyArgs.add(normalizedArg); } } @@ -134,7 +144,7 @@ public class DataNormalizer { return toLegacyFromDataContainer((DataContainerNode) normalizedData); } else if (normalizedData instanceof AnyXmlNode) { Node value = ((AnyXmlNode) normalizedData).getValue(); - return value instanceof CompositeNode ? (CompositeNode)value : null; + return value instanceof CompositeNode ? (CompositeNode) value : null; } return null; } @@ -169,7 +179,7 @@ public class DataNormalizer { for (NormalizedNode child : node.getValue()) { if (child instanceof MixinNode && child instanceof NormalizedNodeContainer) { builder.addAll(toLegacyNodesFromMixin((NormalizedNodeContainer) child)); - } else if( child instanceof UnkeyedListNode) { + } else if (child instanceof UnkeyedListNode) { builder.addAll(toLegacyNodesFromUnkeyedList((UnkeyedListNode) child)); } else { addToBuilder(builder, toLegacy(child)); diff --git a/opendaylight/md-sal/sal-test-model/pom.xml b/opendaylight/md-sal/sal-test-model/pom.xml index 8d29b981dc..11a0ef211a 100644 --- a/opendaylight/md-sal/sal-test-model/pom.xml +++ b/opendaylight/md-sal/sal-test-model/pom.xml @@ -14,6 +14,10 @@ org.opendaylight.yangtools yang-binding + + org.opendaylight.yangtools.model + yang-ext + sal-test-model diff --git a/opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-mdsal-augment-test.yang b/opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-mdsal-augment-test.yang new file mode 100644 index 0000000000..ddd7687628 --- /dev/null +++ b/opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-mdsal-augment-test.yang @@ -0,0 +1,93 @@ +module opendaylight-mdsal-augment-test { + + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:augment"; + prefix aug-test; + + import opendaylight-mdsal-list-test { + prefix test; + } + import yang-ext { + prefix ext; + } + + description + "This module contains a collection of YANG augmentations used for + some test cases."; + + revision 2014-07-09 { + description + "Test model for testing data broker with nested lists."; + } + + grouping leaf-from-grouping { + leaf leaf-from-grouping { + type string; + } + } + + grouping complex-from-grouping { + container container-with-uses { + uses leaf-from-grouping; + } + list list-via-uses { + key "name"; + leaf name { + type string; + } + } + + } + + augment "/test:top/test:top-level-list" { + ext:augment-identifier tree-leaf-only-uses-augment; + uses leaf-from-grouping; + } + + augment "/test:put-top/test:input/test:top-level-list" { + ext:augment-identifier rpc-leaf-only-uses-augment; + uses leaf-from-grouping; + } + + augment "/test:top/test:top-level-list" { + ext:augment-identifier tree-complex-uses-augment; + uses complex-from-grouping; + } + + augment "/test:put-top/test:input/test:top-level-list" { + ext:augment-identifier rpc-complex-uses-augment; + uses complex-from-grouping; + } + + augment "/test:top/test:top-level-list" { + ext:augment-identifier tree-leaf-only-augment; + + leaf simple-value { + type string; + } + } + + augment "/test:top/test:top-level-list" { + ext:augment-identifier tree-second-leaf-only-augment; + + leaf second-simple-value { + type string; + } + } + + augment "/test:put-top/test:input/test:top-level-list" { + ext:augment-identifier rpc-leaf-only-augment; + + leaf simple-value { + type string; + } + } + + augment "/test:put-top/test:input/test:top-level-list" { + ext:augment-identifier rpc-second-leaf-only-augment; + + leaf second-simple-value { + type string; + } + } + +} \ No newline at end of file