X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-data-util%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Futil%2FCompositeNodeDataWithSchema.java;h=8d6bf20a5db4acb109bf9b9af1194dd1b2e4575c;hb=bb60da5fe2d1928defb46ed92b290cfff93dcd81;hp=58f1975cd72037c667a028c979a2bd1572a41237;hpb=085e16356ce77b75dfe5ef74e3a691dab666aa98;p=yangtools.git diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/CompositeNodeDataWithSchema.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/CompositeNodeDataWithSchema.java index 58f1975cd7..8d6bf20a5d 100644 --- a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/CompositeNodeDataWithSchema.java +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/CompositeNodeDataWithSchema.java @@ -9,6 +9,7 @@ package org.opendaylight.yangtools.yang.data.util; import static com.google.common.base.Preconditions.checkArgument; +import com.google.common.annotations.Beta; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import java.io.IOException; @@ -17,14 +18,17 @@ import java.util.Collection; import java.util.Deque; import java.util.List; import java.util.Map.Entry; -import org.opendaylight.yangtools.odlext.model.api.YangModeledAnyXmlSchemaNode; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.odlext.model.api.YangModeledAnyxmlSchemaNode; +import org.opendaylight.yangtools.rfc7952.data.api.StreamWriterMetadataExtension; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; -import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; +import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode; import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ContainerLike; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; @@ -38,6 +42,66 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; * Represents a node which is composed of multiple simpler nodes. */ public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema { + /** + * Policy on how child nodes should be treated when an attempt is made to add them multiple times. + */ + @Beta + public enum ChildReusePolicy { + /** + * Do not consider any existing nodes at all, just perform a straight append. Multiple occurrences of a child + * will result in multiple children being emitted. This is almost certainly the wrong policy unless the caller + * prevents such a situation from arising via some different mechanism. + */ + NOOP, + /** + * Do not allow duplicate definition of a child node. This would typically be used when a child cannot be + * encountered multiple times, but the caller does not make any provision to detect such a conflict. If a child + * node would end up being defined a second time, {@link DuplicateChildNodeRejectedException} is reported. + */ + REJECT { + @Override + AbstractNodeDataWithSchema appendChild(final Collection> view, + final AbstractNodeDataWithSchema newChild) { + final DataSchemaNode childSchema = newChild.getSchema(); + final AbstractNodeDataWithSchema existing = findExistingChild(view, childSchema); + if (existing != null) { + throw new DuplicateChildNodeRejectedException("Duplicate child " + childSchema.getQName()); + } + return super.appendChild(view, newChild); + } + }, + /** + * Reuse previously-defined child node. This is most appropriate when a child may be visited multiple times + * and the intent is to append content of each visit. A typical usage is list elements with RFC7950 XML + * encoding, where there is no encapsulating element and hence list entries may be interleaved with other + * children. + */ + REUSE { + @Override + AbstractNodeDataWithSchema appendChild(final Collection> view, + final AbstractNodeDataWithSchema newChild) { + final AbstractNodeDataWithSchema existing = findExistingChild(view, newChild.getSchema()); + return existing != null ? existing : super.appendChild(view, newChild); + } + }; + + AbstractNodeDataWithSchema appendChild(final Collection> view, + final AbstractNodeDataWithSchema newChild) { + view.add(newChild); + return newChild; + } + + static @Nullable AbstractNodeDataWithSchema findExistingChild( + final Collection> view, final DataSchemaNode childSchema) { + for (AbstractNodeDataWithSchema existing : view) { + if (childSchema.equals(existing.getSchema())) { + return existing; + } + } + return null; + } + } + /** * nodes which were added to schema via augmentation and are present in data input. */ @@ -53,23 +117,19 @@ public class CompositeNodeDataWithSchema extends Abstr super(schema); } - private AbstractNodeDataWithSchema addChild(final DataSchemaNode schema) { - AbstractNodeDataWithSchema newChild = addSimpleChild(schema); - return newChild == null ? addCompositeChild(schema) : newChild; - } - - public void addChild(final AbstractNodeDataWithSchema newChild) { + void addChild(final AbstractNodeDataWithSchema newChild) { children.add(newChild); } - public AbstractNodeDataWithSchema addChild(final Deque schemas) { + public final AbstractNodeDataWithSchema addChild(final Deque schemas, + final ChildReusePolicy policy) { checkArgument(!schemas.isEmpty(), "Expecting at least one schema"); // Pop the first node... final DataSchemaNode schema = schemas.pop(); if (schemas.isEmpty()) { // Simple, direct node - return addChild(schema); + return addChild(schema, policy); } // The choice/case mess, reuse what we already popped @@ -83,9 +143,11 @@ public class CompositeNodeDataWithSchema extends Abstr caseCandidate.getClass()); final CaseSchemaNode caseNode = (CaseSchemaNode) caseCandidate; - AugmentationSchemaNode augSchema = null; + final AugmentationSchemaNode augSchema; if (choiceCandidate.isAugmenting()) { augSchema = findCorrespondingAugment(getSchema(), choiceCandidate); + } else { + augSchema = null; } // looking for existing choice @@ -100,30 +162,42 @@ public class CompositeNodeDataWithSchema extends Abstr if (caseNodeDataWithSchema == null) { ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode); childNodes.add(choiceNodeDataWithSchema); - caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode); + caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode, ChildReusePolicy.NOOP); } - return caseNodeDataWithSchema.addChild(schemas); + return caseNodeDataWithSchema.addChild(schemas, policy); + } + + private AbstractNodeDataWithSchema addChild(final DataSchemaNode schema, final ChildReusePolicy policy) { + AbstractNodeDataWithSchema newChild = addSimpleChild(schema, policy); + return newChild == null ? addCompositeChild(schema, policy) : newChild; } - private AbstractNodeDataWithSchema addSimpleChild(final DataSchemaNode schema) { - SimpleNodeDataWithSchema newChild = null; + private AbstractNodeDataWithSchema addSimpleChild(final DataSchemaNode schema, final ChildReusePolicy policy) { + final SimpleNodeDataWithSchema newChild; if (schema instanceof LeafSchemaNode) { newChild = new LeafNodeDataWithSchema((LeafSchemaNode) schema); - } else if (schema instanceof AnyXmlSchemaNode) { - // YangModeledAnyXmlSchemaNode is handled by addCompositeChild method. - if (schema instanceof YangModeledAnyXmlSchemaNode) { + } else if (schema instanceof AnyxmlSchemaNode) { + // YangModeledAnyxmlSchemaNode is handled by addCompositeChild method. + if (schema instanceof YangModeledAnyxmlSchemaNode) { return null; } - newChild = new AnyXmlNodeDataWithSchema((AnyXmlSchemaNode) schema); + newChild = new AnyXmlNodeDataWithSchema((AnyxmlSchemaNode) schema); + } else if (schema instanceof AnydataSchemaNode) { + newChild = new AnydataNodeDataWithSchema((AnydataSchemaNode) schema); } else { return null; } - AugmentationSchemaNode augSchema = null; + final AugmentationSchemaNode augSchema; if (schema.isAugmenting()) { augSchema = findCorrespondingAugment(getSchema(), schema); + } else { + augSchema = null; } + + // FIXME: 7.0.0: use policy to determine if we should reuse or replace the child + if (augSchema != null) { augmentationsToChild.put(augSchema, newChild); } else { @@ -152,32 +226,31 @@ public class CompositeNodeDataWithSchema extends Abstr return null; } - AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) { + AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema, final ChildReusePolicy policy) { final CompositeNodeDataWithSchema newChild; if (schema instanceof ListSchemaNode) { newChild = new ListNodeDataWithSchema((ListSchemaNode) schema); } else if (schema instanceof LeafListSchemaNode) { newChild = new LeafListNodeDataWithSchema((LeafListSchemaNode) schema); - } else if (schema instanceof ContainerSchemaNode) { - newChild = new ContainerNodeDataWithSchema((ContainerSchemaNode) schema); - } else if (schema instanceof YangModeledAnyXmlSchemaNode) { - newChild = new YangModeledAnyXmlNodeDataWithSchema((YangModeledAnyXmlSchemaNode)schema); + } else if (schema instanceof ContainerLike) { + newChild = new ContainerNodeDataWithSchema((ContainerLike) schema); + } else if (schema instanceof YangModeledAnyxmlSchemaNode) { + newChild = new YangModeledAnyXmlNodeDataWithSchema((YangModeledAnyxmlSchemaNode)schema); } else { newChild = new CompositeNodeDataWithSchema<>(schema); } - addCompositeChild(newChild); - return newChild; + return addCompositeChild(newChild, policy); } - void addCompositeChild(final CompositeNodeDataWithSchema newChild) { - AugmentationSchemaNode augSchema = findCorrespondingAugment(getSchema(), newChild.getSchema()); - if (augSchema != null) { - augmentationsToChild.put(augSchema, newChild); - } else { - addChild(newChild); - } + final AbstractNodeDataWithSchema addCompositeChild(final CompositeNodeDataWithSchema newChild, + final ChildReusePolicy policy) { + final AugmentationSchemaNode augSchema = findCorrespondingAugment(getSchema(), newChild.getSchema()); + final Collection> view = augSchema == null ? children + : augmentationsToChild.get(augSchema); + + return policy.appendChild(view, newChild); } /** @@ -189,9 +262,10 @@ public class CompositeNodeDataWithSchema extends Abstr } @Override - public void write(final NormalizedNodeStreamWriter writer) throws IOException { + public void write(final NormalizedNodeStreamWriter writer, final StreamWriterMetadataExtension metaWriter) + throws IOException { for (AbstractNodeDataWithSchema child : children) { - child.write(writer); + child.write(writer, metaWriter); } for (Entry>> augmentationToChild : augmentationsToChild.asMap().entrySet()) { @@ -202,7 +276,7 @@ public class CompositeNodeDataWithSchema extends Abstr augmentationToChild.getKey())); for (AbstractNodeDataWithSchema nodeDataWithSchema : childsFromAgumentation) { - nodeDataWithSchema.write(writer); + nodeDataWithSchema.write(writer, metaWriter); } writer.endNode(); @@ -222,7 +296,7 @@ public class CompositeNodeDataWithSchema extends Abstr final DataSchemaNode child) { if (parent instanceof AugmentationTarget && !(parent instanceof ChoiceSchemaNode)) { for (AugmentationSchemaNode augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) { - DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName()); + DataSchemaNode childInAugmentation = augmentation.dataChildByName(child.getQName()); if (childInAugmentation != null) { return augmentation; }