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%2FNormalizedNodeContainerModificationStrategy.java;h=e5c4d09033b966d5f8e11a149461a4c6aa6cd768;hb=89614bda5018d15327da0d32ff419a6a62cb8b1f;hp=e868dc92aca62a7d7c4726169cbed9622df48cfd;hpb=ba3c2fa5ebabf5d160547fe63408b2f35f26cf23;p=yangtools.git diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/NormalizedNodeContainerModificationStrategy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/NormalizedNodeContainerModificationStrategy.java index e868dc92ac..e5c4d09033 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/NormalizedNodeContainerModificationStrategy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/NormalizedNodeContainerModificationStrategy.java @@ -7,14 +7,13 @@ */ 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.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import java.util.Collection; +import java.util.Map; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -23,6 +22,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode; import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType; +import org.opendaylight.yangtools.yang.data.api.schema.tree.ModifiedNodeDoesNotExistException; import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.MutableTreeNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNodeFactory; @@ -35,15 +35,11 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMa import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedLeafSetNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; -import org.opendaylight.yangtools.yang.model.api.ChoiceNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import java.util.Map; - -import static com.google.common.base.Preconditions.checkArgument; - abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation { private final Class> nodeClass; @@ -54,26 +50,15 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp @Override public void verifyStructure(final ModifiedNode modification) throws IllegalArgumentException { - if (modification.getType() == ModificationType.WRITE) { - - } for (ModifiedNode childModification : modification.getChildren()) { resolveChildOperation(childModification.getIdentifier()).verifyStructure(childModification); } } - @Override - protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification, - final Optional current) throws DataValidationFailedException { - // FIXME: Implement proper write check for replacement of node container - // prerequisite is to have transaction chain available for clients - // otherwise this will break chained writes to same node. - } - @SuppressWarnings("rawtypes") @Override protected void verifyWrittenStructure(final NormalizedNode writtenValue) { - checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass); + checkArgument(nodeClass.isInstance(writtenValue), "Node %s is not of type %s", writtenValue, nodeClass); checkArgument(writtenValue instanceof NormalizedNodeContainer); NormalizedNodeContainer container = (NormalizedNodeContainer) writtenValue; @@ -95,7 +80,7 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp final NormalizedNode newValue = modification.getWrittenValue(); final TreeNode newValueMeta = TreeNodeFactory.createTreeNode(newValue, version); - if (Iterables.isEmpty(modification.getChildren())) { + if (modification.getChildren().isEmpty()) { return newValueMeta; } @@ -109,6 +94,11 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp * As it turns out, once we materialize the written data, we can share the * code path with the subtree change. So let's create an unsealed TreeNode * and run the common parts on it -- which end with the node being sealed. + * + * FIXME: this code needs to be moved out from the prepare() path and into + * the read() and seal() paths. Merging of writes needs to be charged + * to the code which originated this, not to the code which is + * attempting to make it visible. */ final MutableTreeNode mutable = newValueMeta.mutable(); mutable.setSubtreeVersion(version); @@ -119,12 +109,22 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp return mutateChildren(mutable, dataBuilder, version, modification.getChildren()); } + /** + * Applies write/remove diff operation for each modification child in modification subtree. + * Operation also sets the Data tree references for each Tree Node (Index Node) in meta (MutableTreeNode) structure. + * + * @param meta MutableTreeNode (IndexTreeNode) + * @param data DataBuilder + * @param nodeVersion Version of TreeNode + * @param modifications modification operations to apply + * @return Sealed immutable copy of TreeNode structure with all Data Node references set. + */ @SuppressWarnings({ "rawtypes", "unchecked" }) private TreeNode mutateChildren(final MutableTreeNode meta, final NormalizedNodeContainerBuilder data, final Version nodeVersion, final Iterable modifications) { for (ModifiedNode mod : modifications) { - final PathArgument id = mod.getIdentifier(); + final YangInstanceIdentifier.PathArgument id = mod.getIdentifier(); final Optional cm = meta.getChild(id); Optional result = resolveChildOperation(id).apply(mod, cm, nodeVersion); @@ -146,6 +146,7 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta, final Version version) { // For Node Containers - merge is same as subtree change - we only replace children. + modification.resolveModificationType(ModificationType.SUBTREE_MODIFIED); return applySubtreeChange(modification, currentMeta, version); } @@ -155,32 +156,46 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp final MutableTreeNode newMeta = currentMeta.mutable(); newMeta.setSubtreeVersion(version); + /* + * The user has issued an empty merge operation. In this case we do not perform + * a data tree mutation, do not pass GO, and do not collect useless garbage. + */ + final Collection children = modification.getChildren(); + if (children.isEmpty()) { + newMeta.setData(currentMeta.getData()); + return newMeta.seal(); + } + @SuppressWarnings("rawtypes") NormalizedNodeContainerBuilder dataBuilder = createBuilder(currentMeta.getData()); - return mutateChildren(newMeta, dataBuilder, version, modification.getChildren()); + return mutateChildren(newMeta, dataBuilder, version, children); } @Override - protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification, + protected void checkSubtreeModificationApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional current) throws DataValidationFailedException { + if (!modification.getOriginal().isPresent() && !current.isPresent()) { + throw new ModifiedNodeDoesNotExistException(path, String.format("Node %s does not exist. Cannot apply modification to its children.", path)); + } + SchemaAwareApplyOperation.checkConflicting(path, current.isPresent(), "Node was deleted by other transaction."); checkChildPreconditions(path, modification, current); } - private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional current) throws DataValidationFailedException { + private void checkChildPreconditions(final YangInstanceIdentifier path, final NodeModification modification, final Optional current) throws DataValidationFailedException { final TreeNode currentMeta = current.get(); for (NodeModification childMod : modification.getChildren()) { - final PathArgument childId = childMod.getIdentifier(); + final YangInstanceIdentifier.PathArgument childId = childMod.getIdentifier(); final Optional childMeta = currentMeta.getChild(childId); - InstanceIdentifier childPath = path.node(childId); + YangInstanceIdentifier childPath = path.node(childId); resolveChildOperation(childId).checkApplicable(childPath, childMod, childMeta); } } @Override - protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification, + protected void checkMergeApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional current) throws DataValidationFailedException { if(current.isPresent()) { checkChildPreconditions(path, modification,current); @@ -192,31 +207,31 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy { - private final Map childNodes; + private final Map childNodes; - public ChoiceModificationStrategy(final ChoiceNode schemaNode) { - super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class); - ImmutableMap.Builder child = ImmutableMap.builder(); + public ChoiceModificationStrategy(final ChoiceSchemaNode schemaNode) { + super(ChoiceNode.class); + ImmutableMap.Builder child = ImmutableMap.builder(); for (ChoiceCaseNode caze : schemaNode.getCases()) { for (DataSchemaNode cazeChild : caze.getChildNodes()) { SchemaAwareApplyOperation childNode = SchemaAwareApplyOperation.from(cazeChild); - child.put(new NodeIdentifier(cazeChild.getQName()), childNode); + child.put(new YangInstanceIdentifier.NodeIdentifier(cazeChild.getQName()), childNode); } } childNodes = child.build(); } @Override - public Optional getChild(final PathArgument child) { + public Optional getChild(final YangInstanceIdentifier.PathArgument child) { return Optional.fromNullable(childNodes.get(child)); } @Override @SuppressWarnings("rawtypes") protected DataContainerNodeBuilder createBuilder(final NormalizedNode original) { - checkArgument(original instanceof org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode); - return ImmutableChoiceNodeBuilder.create((org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode) original); + checkArgument(original instanceof ChoiceNode); + return ImmutableChoiceNodeBuilder.create((ChoiceNode) original); } } @@ -230,6 +245,11 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp entryStrategy = Optional. of(new ValueNodeModificationStrategy.LeafSetEntryModificationStrategy(schema)); } + @Override + boolean isOrdered() { + return true; + } + @SuppressWarnings("rawtypes") @Override protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode original) { @@ -238,8 +258,8 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp } @Override - public Optional getChild(final PathArgument identifier) { - if (identifier instanceof NodeWithValue) { + public Optional getChild(final YangInstanceIdentifier.PathArgument identifier) { + if (identifier instanceof YangInstanceIdentifier.NodeWithValue) { return entryStrategy; } return Optional.absent(); @@ -255,6 +275,11 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp entryStrategy = Optional. of(new DataNodeContainerModificationStrategy.ListEntryModificationStrategy(schema)); } + @Override + boolean isOrdered() { + return true; + } + @SuppressWarnings("rawtypes") @Override protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode original) { @@ -263,8 +288,8 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp } @Override - public Optional getChild(final PathArgument identifier) { - if (identifier instanceof NodeIdentifierWithPredicates) { + public Optional getChild(final YangInstanceIdentifier.PathArgument identifier) { + if (identifier instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) { return entryStrategy; } return Optional.absent(); @@ -294,8 +319,8 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp } @Override - public Optional getChild(final PathArgument identifier) { - if (identifier instanceof NodeWithValue) { + public Optional getChild(final YangInstanceIdentifier.PathArgument identifier) { + if (identifier instanceof YangInstanceIdentifier.NodeWithValue) { return entryStrategy; } return Optional.absent(); @@ -319,8 +344,8 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp } @Override - public Optional getChild(final PathArgument identifier) { - if (identifier instanceof NodeIdentifierWithPredicates) { + public Optional getChild(final YangInstanceIdentifier.PathArgument identifier) { + if (identifier instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) { return entryStrategy; } return Optional.absent();