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 java.util.Map;
-
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
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;
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.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-
abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation {
private final Class<? extends NormalizedNode<?, ?>> nodeClass;
@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 YangInstanceIdentifier path, final NodeModification modification,
- final Optional<TreeNode> 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;
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<ModifiedNode> modifications) {
for (ModifiedNode mod : modifications) {
- final PathArgument id = mod.getIdentifier();
+ final YangInstanceIdentifier.PathArgument id = mod.getIdentifier();
final Optional<TreeNode> cm = meta.getChild(id);
Optional<TreeNode> result = resolveChildOperation(id).apply(mod, cm, nodeVersion);
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 Iterable<ModifiedNode> children = modification.getChildren();
+ if (Iterables.isEmpty(children)) {
+ 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 YangInstanceIdentifier path, final NodeModification modification,
final Optional<TreeNode> current) throws DataValidationFailedException {
- checkDoesNotExists(path, modification.getOriginal().isPresent() || current.isPresent(), "Node does not exist. Could not modify its children.");
+ 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 static void checkDoesNotExists(final YangInstanceIdentifier path, final boolean condition, final String message) throws DataValidationFailedException {
- if(!condition) {
- throw new ModifiedNodeDoesNotExistException(path,message);
- }
- }
-
private void checkChildPreconditions(final YangInstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> 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<TreeNode> childMeta = currentMeta.getChild(childId);
YangInstanceIdentifier childPath = path.node(childId);
public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy {
- private final Map<PathArgument, ModificationApplyOperation> childNodes;
+ private final Map<YangInstanceIdentifier.PathArgument, ModificationApplyOperation> childNodes;
public ChoiceModificationStrategy(final ChoiceNode schemaNode) {
super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class);
- ImmutableMap.Builder<PathArgument, ModificationApplyOperation> child = ImmutableMap.builder();
+ ImmutableMap.Builder<YangInstanceIdentifier.PathArgument, ModificationApplyOperation> 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<ModificationApplyOperation> getChild(final PathArgument child) {
+ public Optional<ModificationApplyOperation> getChild(final YangInstanceIdentifier.PathArgument child) {
return Optional.fromNullable(childNodes.get(child));
}
entryStrategy = Optional.<ModificationApplyOperation> of(new ValueNodeModificationStrategy.LeafSetEntryModificationStrategy(schema));
}
+ @Override
+ boolean isOrdered() {
+ return true;
+ }
+
@SuppressWarnings("rawtypes")
@Override
protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
}
@Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
- if (identifier instanceof NodeWithValue) {
+ public Optional<ModificationApplyOperation> getChild(final YangInstanceIdentifier.PathArgument identifier) {
+ if (identifier instanceof YangInstanceIdentifier.NodeWithValue) {
return entryStrategy;
}
return Optional.absent();
entryStrategy = Optional.<ModificationApplyOperation> of(new DataNodeContainerModificationStrategy.ListEntryModificationStrategy(schema));
}
+ @Override
+ boolean isOrdered() {
+ return true;
+ }
+
@SuppressWarnings("rawtypes")
@Override
protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
}
@Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
- if (identifier instanceof NodeIdentifierWithPredicates) {
+ public Optional<ModificationApplyOperation> getChild(final YangInstanceIdentifier.PathArgument identifier) {
+ if (identifier instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) {
return entryStrategy;
}
return Optional.absent();
}
@Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
- if (identifier instanceof NodeWithValue) {
+ public Optional<ModificationApplyOperation> getChild(final YangInstanceIdentifier.PathArgument identifier) {
+ if (identifier instanceof YangInstanceIdentifier.NodeWithValue) {
return entryStrategy;
}
return Optional.absent();
}
@Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
- if (identifier instanceof NodeIdentifierWithPredicates) {
+ public Optional<ModificationApplyOperation> getChild(final YangInstanceIdentifier.PathArgument identifier) {
+ if (identifier instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) {
return entryStrategy;
}
return Optional.absent();