X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-data-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Fimpl%2Fschema%2Ftree%2FChoiceModificationStrategy.java;h=38edd7bb2f088f5b7cb4f20d10edf1de37223f49;hb=5500c3ce51088ed6de1adedd35f52662a8304b1e;hp=0f91a45c61f91e925a45d9493e36f4c354c9b987;hpb=adc2275288a6055dda77692b5a742835eb15af3b;p=yangtools.git diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ChoiceModificationStrategy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ChoiceModificationStrategy.java index 0f91a45c61..38edd7bb2f 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ChoiceModificationStrategy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ChoiceModificationStrategy.java @@ -10,12 +10,26 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree; import static com.google.common.base.Preconditions.checkArgument; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicates; +import com.google.common.base.Verify; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; +import java.util.Collection; +import java.util.HashMap; import java.util.Map; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import java.util.Map.Entry; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes; import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; @@ -23,27 +37,38 @@ import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; final class ChoiceModificationStrategy extends AbstractNodeContainerModificationStrategy { - private final Map childNodes; + private final Map childNodes; + // FIXME: enforce leaves not coming from two case statements at the same time + private final Map> exclusions; + private final Map caseEnforcers; ChoiceModificationStrategy(final ChoiceSchemaNode schemaNode, final TreeType treeType) { super(ChoiceNode.class, treeType); - final ImmutableMap.Builder child = ImmutableMap.builder(); + final Builder childBuilder = ImmutableMap.builder(); + final Builder enforcerBuilder = ImmutableMap.builder(); for (final ChoiceCaseNode caze : schemaNode.getCases()) { - if(SchemaAwareApplyOperation.belongsToTree(treeType,caze)) { - for (final DataSchemaNode cazeChild : caze.getChildNodes()) { - if(SchemaAwareApplyOperation.belongsToTree(treeType,cazeChild)) { - final SchemaAwareApplyOperation childNode = SchemaAwareApplyOperation.from(cazeChild,treeType); - child.put(new YangInstanceIdentifier.NodeIdentifier(cazeChild.getQName()), childNode); - } + final CaseEnforcer enforcer = CaseEnforcer.forTree(caze, treeType); + if (enforcer != null) { + for (final Entry e : enforcer.getChildEntries()) { + childBuilder.put(e.getKey(), SchemaAwareApplyOperation.from(e.getValue(), treeType)); + enforcerBuilder.put(e.getKey(), enforcer); } } } - childNodes = child.build(); + childNodes = childBuilder.build(); + caseEnforcers = enforcerBuilder.build(); + + final Map> exclusionsBuilder = new HashMap<>(); + for (CaseEnforcer e : caseEnforcers.values()) { + exclusionsBuilder.put(e, ImmutableList.copyOf( + Collections2.filter(caseEnforcers.values(), Predicates.not(Predicates.equalTo(e))))); + } + exclusions = ImmutableMap.copyOf(exclusionsBuilder); } @Override - public Optional getChild(final YangInstanceIdentifier.PathArgument child) { + public Optional getChild(final PathArgument child) { return Optional.fromNullable(childNodes.get(child)); } @@ -53,4 +78,61 @@ final class ChoiceModificationStrategy extends AbstractNodeContainerModification checkArgument(original instanceof ChoiceNode); return ImmutableChoiceNodeBuilder.create((ChoiceNode) original); } -} \ No newline at end of file + + @Override + void verifyStructure(final NormalizedNode writtenValue, final boolean verifyChildren) { + if(verifyChildrenStructure() && verifyChildren) { + enforceCases(writtenValue); + } + super.verifyStructure(writtenValue, verifyChildren); + } + + private void enforceCases(final TreeNode tree) { + enforceCases(tree.getData()); + } + + private void enforceCases(final NormalizedNode normalizedNode) { + Verify.verify(normalizedNode instanceof ChoiceNode); + final Collection> children = ((ChoiceNode) normalizedNode).getValue(); + if (!children.isEmpty()) { + final DataContainerChild firstChild = children.iterator().next(); + final CaseEnforcer enforcer = caseEnforcers.get(firstChild.getIdentifier()); + Verify.verifyNotNull(enforcer, "Case enforcer cannot be null. Most probably, child node %s of choice node %s does not belong in current tree type.", firstChild.getIdentifier(), normalizedNode.getIdentifier()); + + // Make sure no leaves from other cases are present + for (CaseEnforcer other : exclusions.get(enforcer)) { + for (NodeIdentifier id : other.getChildIdentifiers()) { + final Optional> maybeChild = NormalizedNodes.getDirectChild(normalizedNode, id); + Preconditions.checkArgument(!maybeChild.isPresent(), + "Child %s (from case %s) implies non-presence of child %s (from case %s), which is %s", + firstChild.getIdentifier(), enforcer, id, other, maybeChild.orNull()); + } + } + + // Make sure all mandatory children are present + enforcer.enforceOnTreeNode(normalizedNode); + } + } + + @Override + protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta, final Version version) { + final TreeNode ret = super.applyMerge(modification, currentMeta, version); + enforceCases(ret); + return ret; + } + + @Override + protected TreeNode applyWrite(final ModifiedNode modification, final Optional currentMeta, + final Version version) { + final TreeNode ret = super.applyWrite(modification, currentMeta, version); + enforceCases(ret); + return ret; + } + + @Override + protected TreeNode applyTouch(final ModifiedNode modification, final TreeNode currentMeta, final Version version) { + final TreeNode ret = super.applyTouch(modification, currentMeta, version); + enforceCases(ret); + return ret; + } +}