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=62c6ebcad98463b5394419441184ceb8ac73ed25;hb=bf405586fc69c3781311cfb8ac19ba93b670ec8d;hp=dbc1fe3536321112e3ac75e3ba9ea87fd38234a7;hpb=b43b9ed6f627a4a1d2ecc6081ed4f0024761e4a3;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 dbc1fe3536..62c6ebcad9 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 @@ -8,12 +8,28 @@ 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; @@ -21,23 +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) { - super(ChoiceNode.class); - ImmutableMap.Builder child = ImmutableMap.builder(); + ChoiceModificationStrategy(final ChoiceSchemaNode schemaNode, final TreeType treeType) { + super(ChoiceNode.class, treeType); - for (ChoiceCaseNode caze : schemaNode.getCases()) { - for (DataSchemaNode cazeChild : caze.getChildNodes()) { - SchemaAwareApplyOperation childNode = SchemaAwareApplyOperation.from(cazeChild); - child.put(new YangInstanceIdentifier.NodeIdentifier(cazeChild.getQName()), childNode); + final Builder childBuilder = ImmutableMap.builder(); + final Builder enforcerBuilder = ImmutableMap.builder(); + for (final ChoiceCaseNode caze : schemaNode.getCases()) { + 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)); } @@ -47,4 +78,68 @@ 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; + } + + @Override + protected NormalizedNode createEmptyValue(NormalizedNode original) { + checkArgument(original instanceof ChoiceNode); + return ImmutableChoiceNodeBuilder.create().withNodeIdentifier(((ChoiceNode) original).getIdentifier()).build(); + } +} +