package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
*/
final class AlwaysFailOperation implements ModificationApplyOperation {
@Override
- public Optional<StoreMetadataNode> apply(final NodeModification modification,
- final Optional<StoreMetadataNode> storeMeta, final UnsignedLong subtreeVersion) {
+ public Optional<TreeNode> apply(final ModifiedNode modification,
+ final Optional<TreeNode> storeMeta, final UnsignedLong subtreeVersion) {
throw new IllegalStateException("Schema Context is not available.");
}
@Override
- public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> storeMetadata) {
+ public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<TreeNode> storeMetadata) {
throw new IllegalStateException("Schema Context is not available.");
}
}
@Override
- public void verifyStructure(final NodeModification modification) {
+ public void verifyStructure(final ModifiedNode modification) {
throw new IllegalStateException("Schema Context is not available.");
}
}
\ No newline at end of file
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.slf4j.Logger;
private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
private ModificationApplyOperation applyOper = new AlwaysFailOperation();
private SchemaContext currentSchemaContext;
- private StoreMetadataNode rootNode;
+ private TreeNode rootNode;
- public InMemoryDataTree(StoreMetadataNode rootNode, final SchemaContext schemaContext) {
+ public InMemoryDataTree(final TreeNode rootNode, final SchemaContext schemaContext) {
this.rootNode = Preconditions.checkNotNull(rootNode);
if (schemaContext != null) {
}
@Override
- public void validate(DataTreeModification modification) throws DataPreconditionFailedException {
+ public void validate(final DataTreeModification modification) throws DataPreconditionFailedException {
Preconditions.checkArgument(modification instanceof InMemoryDataTreeModification, "Invalid modification class %s", modification.getClass());
final InMemoryDataTreeModification m = (InMemoryDataTreeModification)modification;
- m.getStrategy().checkApplicable(PUBLIC_ROOT_PATH, m.getRootModification(), Optional.of(rootNode));
+ m.getStrategy().checkApplicable(PUBLIC_ROOT_PATH, m.getRootModification(), Optional.<TreeNode>of(rootNode));
}
@Override
- public synchronized DataTreeCandidate prepare(DataTreeModification modification) {
+ public synchronized DataTreeCandidate prepare(final DataTreeModification modification) {
Preconditions.checkArgument(modification instanceof InMemoryDataTreeModification, "Invalid modification class %s", modification.getClass());
final InMemoryDataTreeModification m = (InMemoryDataTreeModification)modification;
- final NodeModification root = m.getRootModification();
+ final ModifiedNode root = m.getRootModification();
- if (root.getModificationType() == ModificationType.UNMODIFIED) {
+ if (root.getType() == ModificationType.UNMODIFIED) {
return new NoopDataTreeCandidate(PUBLIC_ROOT_PATH, root);
}
rwLock.writeLock().lock();
try {
- // FIXME: rootNode needs to be a read-write snapshot here...
- final Optional<StoreMetadataNode> newRoot = m.getStrategy().apply(m.getRootModification(), Optional.of(rootNode), StoreUtils.increase(rootNode.getSubtreeVersion()));
+ final Optional<TreeNode> newRoot = m.getStrategy().apply(m.getRootModification(), Optional.<TreeNode>of(rootNode), StoreUtils.increase(rootNode.getSubtreeVersion()));
Preconditions.checkState(newRoot.isPresent(), "Apply strategy failed to produce root node");
return new InMemoryDataTreeCandidate(PUBLIC_ROOT_PATH, root, rootNode, newRoot.get());
} finally {
}
@Override
- public synchronized void commit(DataTreeCandidate candidate) {
+ public synchronized void commit(final DataTreeCandidate candidate) {
if (candidate instanceof NoopDataTreeCandidate) {
return;
}
Preconditions.checkArgument(candidate instanceof InMemoryDataTreeCandidate, "Invalid candidate class %s", candidate.getClass());
final InMemoryDataTreeCandidate c = (InMemoryDataTreeCandidate)candidate;
- LOG.debug("Updating Store snapshot version: {} with version:{}", rootNode.getSubtreeVersion(), c.getAfterRoot().getSubtreeVersion());
+ LOG.debug("Updating datastore from {} to {}", rootNode, c.getAfterRoot());
if (LOG.isTraceEnabled()) {
LOG.trace("Data Tree is {}", StoreUtils.toStringTree(c.getAfterRoot().getData()));
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidateNode;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
final class InMemoryDataTreeCandidate extends AbstractDataTreeCandidate {
private static abstract class AbstractNode implements DataTreeCandidateNode {
- private final StoreMetadataNode newMeta;
- private final StoreMetadataNode oldMeta;
- private final NodeModification mod;
+ private final ModifiedNode mod;
+ private final TreeNode newMeta;
+ private final TreeNode oldMeta;
- protected AbstractNode(final NodeModification mod,
- final StoreMetadataNode oldMeta, final StoreMetadataNode newMeta) {
+ protected AbstractNode(final ModifiedNode mod,
+ final TreeNode oldMeta, final TreeNode newMeta) {
this.newMeta = newMeta;
this.oldMeta = oldMeta;
this.mod = Preconditions.checkNotNull(mod);
}
- protected final NodeModification getMod() {
+ protected final ModifiedNode getMod() {
return mod;
}
- protected final StoreMetadataNode getNewMeta() {
+ protected final TreeNode getNewMeta() {
return newMeta;
}
- protected final StoreMetadataNode getOldMeta() {
+ protected final TreeNode getOldMeta() {
return oldMeta;
}
- private static final StoreMetadataNode childMeta(final StoreMetadataNode parent, final PathArgument id) {
- return parent == null ? null : parent.getChild(id).orNull();
+ private static final TreeNode childMeta(final TreeNode parent, final PathArgument id) {
+ if (parent != null) {
+ return parent.getChild(id).orNull();
+ } else {
+ return null;
+ }
}
@Override
public Iterable<DataTreeCandidateNode> getChildNodes() {
- return Iterables.transform(mod.getModifications(), new Function<NodeModification, DataTreeCandidateNode>() {
+ return Iterables.transform(mod.getChildren(), new Function<ModifiedNode, DataTreeCandidateNode>() {
@Override
- public DataTreeCandidateNode apply(final NodeModification input) {
+ public DataTreeCandidateNode apply(final ModifiedNode input) {
final PathArgument id = input.getIdentifier();
return new ChildNode(input, childMeta(oldMeta, id), childMeta(newMeta, id));
}
@Override
public ModificationType getModificationType() {
- return mod.getModificationType();
+ return mod.getType();
}
- private Optional<NormalizedNode<?, ?>> optionalData(StoreMetadataNode meta) {
- if (meta == null) {
+ private Optional<NormalizedNode<?, ?>> optionalData(final TreeNode meta) {
+ if (meta != null) {
+ return Optional.<NormalizedNode<?,?>>of(meta.getData());
+ } else {
return Optional.absent();
}
- return Optional.<NormalizedNode<?,?>>of(meta.getData());
}
@Override
}
private static final class ChildNode extends AbstractNode {
- public ChildNode(NodeModification mod, StoreMetadataNode oldMeta, StoreMetadataNode newMeta) {
+ public ChildNode(final ModifiedNode mod, final TreeNode oldMeta, final TreeNode newMeta) {
super(mod, oldMeta, newMeta);
}
}
private static final class RootNode extends AbstractNode {
- public RootNode(NodeModification mod, StoreMetadataNode oldMeta, StoreMetadataNode newMeta) {
+ public RootNode(final ModifiedNode mod, final TreeNode oldMeta, final TreeNode newMeta) {
super(mod, oldMeta, newMeta);
}
private final RootNode root;
- InMemoryDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot,
- final StoreMetadataNode oldRoot, final StoreMetadataNode newRoot) {
+ InMemoryDataTreeCandidate(final InstanceIdentifier rootPath, final ModifiedNode modificationRoot,
+ final TreeNode beforeRoot, final TreeNode afterRoot) {
super(rootPath);
- this.root = new RootNode(modificationRoot, oldRoot, newRoot);
+ this.root = new RootNode(modificationRoot, beforeRoot, afterRoot);
}
- StoreMetadataNode getAfterRoot() {
+ TreeNode getAfterRoot() {
return root.getNewMeta();
}
- StoreMetadataNode getBeforeRoot() {
+ TreeNode getBeforeRoot() {
return root.getOldMeta();
}
package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeFactory;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNodeFactory;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import com.google.common.primitives.UnsignedLong;
+
/**
* A factory for creating in-memory data trees.
*/
public final class InMemoryDataTreeFactory implements DataTreeFactory {
- private static final InMemoryDataTreeFactory INSTANCE = new InMemoryDataTreeFactory();
+ private static final InMemoryDataTreeFactory INSTANCE = new InMemoryDataTreeFactory();
- private InMemoryDataTreeFactory() {
- // Never instantiated externally
- }
+ private InMemoryDataTreeFactory() {
+ // Never instantiated externally
+ }
- @Override
- public InMemoryDataTree create() {
- final NodeIdentifier root = new NodeIdentifier(SchemaContext.NAME);
- final NormalizedNode<?, ?> data = Builders.containerBuilder().withNodeIdentifier(root).build();
+ @Override
+ public InMemoryDataTree create() {
+ final NodeIdentifier root = new NodeIdentifier(SchemaContext.NAME);
+ final NormalizedNode<?, ?> data = Builders.containerBuilder().withNodeIdentifier(root).build();
- return new InMemoryDataTree(StoreMetadataNode.createEmpty(data), null);
- }
+ return new InMemoryDataTree(TreeNodeFactory.createTreeNode(data, UnsignedLong.ZERO), null);
+ }
- /**
- * Get an instance of this factory. This method cannot fail.
- *
- * @return Data tree factory instance.
- */
- public static final InMemoryDataTreeFactory getInstance() {
- return INSTANCE;
- }
+ /**
+ * Get an instance of this factory. This method cannot fail.
+ *
+ * @return Data tree factory instance.
+ */
+ public static final InMemoryDataTreeFactory getInstance() {
+ return INSTANCE;
+ }
}
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.TreeNodeUtils;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
private final ModificationApplyOperation strategyTree;
private final InMemoryDataTreeSnapshot snapshot;
- private final NodeModification rootNode;
+ private final ModifiedNode rootNode;
InMemoryDataTreeModification(final InMemoryDataTreeSnapshot snapshot, final ModificationApplyOperation resolver) {
this.snapshot = Preconditions.checkNotNull(snapshot);
this.strategyTree = Preconditions.checkNotNull(resolver);
- this.rootNode = NodeModification.createUnmodified(snapshot.getRootNode());
+ this.rootNode = ModifiedNode.createUnmodified(snapshot.getRootNode());
}
- NodeModification getRootModification() {
+ ModifiedNode getRootModification() {
return rootNode;
}
* the requested path which has been modified. If no such node exists,
* we use the node itself.
*/
- final Entry<InstanceIdentifier, NodeModification> entry = TreeNodeUtils.findClosestsOrFirstMatch(rootNode, path, NodeModification.IS_TERMINAL_PREDICATE);
+ final Entry<InstanceIdentifier, ModifiedNode> entry = TreeNodeUtils.findClosestsOrFirstMatch(rootNode, path, ModifiedNode.IS_TERMINAL_PREDICATE);
final InstanceIdentifier key = entry.getKey();
- final NodeModification mod = entry.getValue();
+ final ModifiedNode mod = entry.getValue();
- final Optional<StoreMetadataNode> result = resolveSnapshot(key, mod);
+ final Optional<TreeNode> result = resolveSnapshot(key, mod);
if (result.isPresent()) {
NormalizedNode<?, ?> data = result.get().getData();
return NormalizedNodeUtils.findNode(key, data, path);
}
}
- private Optional<StoreMetadataNode> resolveSnapshot(final InstanceIdentifier path,
- final NodeModification modification) {
- final Optional<Optional<StoreMetadataNode>> potentialSnapshot = modification.getSnapshotCache();
+ private Optional<TreeNode> resolveSnapshot(final InstanceIdentifier path,
+ final ModifiedNode modification) {
+ final Optional<Optional<TreeNode>> potentialSnapshot = modification.getSnapshotCache();
if(potentialSnapshot.isPresent()) {
return potentialSnapshot.get();
}
}
private OperationWithModification resolveModificationFor(final InstanceIdentifier path) {
- NodeModification modification = rootNode;
+ ModifiedNode modification = rootNode;
// We ensure strategy is present.
ModificationApplyOperation operation = resolveModificationStrategy(path);
for (PathArgument pathArg : path.getPath()) {
package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeSnapshot;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils;
final class InMemoryDataTreeSnapshot implements DataTreeSnapshot {
private final ModificationApplyOperation applyOper;
private final SchemaContext schemaContext;
- private final StoreMetadataNode rootNode;
+ private final TreeNode rootNode;
- InMemoryDataTreeSnapshot(final SchemaContext schemaContext, final StoreMetadataNode rootNode,
+ InMemoryDataTreeSnapshot(final SchemaContext schemaContext, final TreeNode rootNode,
final ModificationApplyOperation applyOper) {
this.schemaContext = Preconditions.checkNotNull(schemaContext);
this.rootNode = Preconditions.checkNotNull(rootNode);
this.applyOper = Preconditions.checkNotNull(applyOper);
}
- StoreMetadataNode getRootNode() {
+ TreeNode getRootNode() {
return rootNode;
}
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
/**
*
- * Operation responsible for applying {@link NodeModification} on tree.
+ * Operation responsible for applying {@link ModifiedNode} on tree.
*
* Operation is composite - operation on top level node consists of
* suboperations on child nodes. This allows to walk operation hierarchy and
* Implementations MUST expose all nested suboperations which operates on child
* nodes expose via {@link #getChild(PathArgument)} method.
* <li>Same suboperations SHOULD be used when invoked via
- * {@link #apply(NodeModification, Optional)} if applicable.
+ * {@link #apply(ModifiedNode, Optional)} if applicable.
*
*
* Hierarchical composite operation which is responsible for applying
* If it is not possible to apply Operation on provided Metadata
* node
* @return new {@link StoreMetadataNode} if operation resulted in updating
- * node, {@link Optional#absent()} if {@link NodeModification}
+ * node, {@link Optional#absent()} if {@link ModifiedNode}
* resulted in deletion of this node.
*/
- Optional<StoreMetadataNode> apply(NodeModification modification, Optional<StoreMetadataNode> storeMeta, UnsignedLong subtreeVersion);
+ Optional<TreeNode> apply(ModifiedNode modification, Optional<TreeNode> storeMeta, UnsignedLong subtreeVersion);
/**
*
* @param modification to be verified.
* @throws IllegalArgumentException If provided NodeModification does not adhere to the structure.
*/
- void verifyStructure(NodeModification modification) throws IllegalArgumentException;
+ void verifyStructure(ModifiedNode modification) throws IllegalArgumentException;
/**
* Returns a suboperation for specified tree node
* false if modification is no applicable
* @throws DataPreconditionFailedException
*/
- void checkApplicable(InstanceIdentifier path, NodeModification modification, Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
+ void checkApplicable(InstanceIdentifier path, NodeModification modification, Optional<TreeNode> current) throws DataPreconditionFailedException;
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+
+/**
+ * Node Modification Node and Tree
+ *
+ * Tree which structurally resembles data tree and captures client modifications
+ * to the data store tree.
+ *
+ * This tree is lazily created and populated via {@link #modifyChild(PathArgument)}
+ * and {@link StoreMetadataNode} which represents original state {@link #getOriginal()}.
+ */
+final class ModifiedNode implements StoreTreeNode<ModifiedNode>, Identifiable<PathArgument>, NodeModification {
+
+ public static final Predicate<ModifiedNode> IS_TERMINAL_PREDICATE = new Predicate<ModifiedNode>() {
+ @Override
+ public boolean apply(final ModifiedNode input) {
+ switch (input.getType()) {
+ case DELETE:
+ case MERGE:
+ case WRITE:
+ return true;
+ case SUBTREE_MODIFIED:
+ case UNMODIFIED:
+ return false;
+ }
+
+ throw new IllegalArgumentException(String.format("Unhandled modification type %s", input.getType()));
+ }
+ };
+ private final PathArgument identifier;
+ private ModificationType modificationType = ModificationType.UNMODIFIED;
+
+
+ private final Optional<TreeNode> original;
+
+ private NormalizedNode<?, ?> value;
+
+ private Optional<TreeNode> snapshotCache;
+
+ private final Map<PathArgument, ModifiedNode> childModification;
+
+ @GuardedBy("this")
+ private boolean sealed = false;
+
+ private ModifiedNode(final PathArgument identifier, final Optional<TreeNode> original) {
+ this.identifier = identifier;
+ this.original = original;
+ childModification = new LinkedHashMap<>();
+ }
+
+ /**
+ *
+ *
+ * @return
+ */
+ public NormalizedNode<?, ?> getWrittenValue() {
+ return value;
+ }
+
+ @Override
+ public PathArgument getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ *
+ * Returns original store metadata
+ * @return original store metadata
+ */
+ @Override
+ public final Optional<TreeNode> getOriginal() {
+ return original;
+ }
+
+ /**
+ * Returns modification type
+ *
+ * @return modification type
+ */
+ @Override
+ public final ModificationType getType() {
+ return modificationType;
+ }
+
+ /**
+ *
+ * Returns child modification if child was modified
+ *
+ * @return Child modification if direct child or it's subtree
+ * was modified.
+ *
+ */
+ @Override
+ public Optional<ModifiedNode> getChild(final PathArgument child) {
+ return Optional.<ModifiedNode> fromNullable(childModification.get(child));
+ }
+
+ /**
+ *
+ * Returns child modification if child was modified, creates {@link ModifiedNode}
+ * for child otherwise.
+ *
+ * If this node's {@link ModificationType} is {@link ModificationType#UNMODIFIED}
+ * changes modification type to {@link ModificationType#SUBTREE_MODIFIED}
+ *
+ * @param child
+ * @return {@link ModifiedNode} for specified child, with {@link #getOriginal()}
+ * containing child metadata if child was present in original data.
+ */
+ public synchronized ModifiedNode modifyChild(final PathArgument child) {
+ checkSealed();
+ clearSnapshot();
+ if (modificationType == ModificationType.UNMODIFIED) {
+ updateModificationType(ModificationType.SUBTREE_MODIFIED);
+ }
+ final ModifiedNode potential = childModification.get(child);
+ if (potential != null) {
+ return potential;
+ }
+
+ final Optional<TreeNode> currentMetadata;
+ if (original.isPresent()) {
+ final TreeNode orig = original.get();
+ currentMetadata = orig.getChild(child);
+ } else {
+ currentMetadata = Optional.absent();
+ }
+
+ ModifiedNode newlyCreated = new ModifiedNode(child, currentMetadata);
+ childModification.put(child, newlyCreated);
+ return newlyCreated;
+ }
+
+ /**
+ *
+ * Returns all recorded direct child modification
+ *
+ * @return all recorded direct child modifications
+ */
+ @Override
+ public Iterable<ModifiedNode> getChildren() {
+ return childModification.values();
+ }
+
+ /**
+ *
+ * Records a delete for associated node.
+ *
+ */
+ public synchronized void delete() {
+ checkSealed();
+ clearSnapshot();
+ updateModificationType(ModificationType.DELETE);
+ childModification.clear();
+ this.value = null;
+ }
+
+ /**
+ *
+ * Records a write for associated node.
+ *
+ * @param value
+ */
+ public synchronized void write(final NormalizedNode<?, ?> value) {
+ checkSealed();
+ clearSnapshot();
+ updateModificationType(ModificationType.WRITE);
+ childModification.clear();
+ this.value = value;
+ }
+
+ public synchronized void merge(final NormalizedNode<?, ?> data) {
+ checkSealed();
+ clearSnapshot();
+ updateModificationType(ModificationType.MERGE);
+ // FIXME: Probably merge with previous value.
+ this.value = data;
+ }
+
+ @GuardedBy("this")
+ private void checkSealed() {
+ Preconditions.checkState(!sealed, "Node Modification is sealed. No further changes allowed.");
+ }
+
+ public synchronized void seal() {
+ sealed = true;
+ clearSnapshot();
+ for(ModifiedNode child : childModification.values()) {
+ child.seal();
+ }
+ }
+
+ private void clearSnapshot() {
+ snapshotCache = null;
+ }
+
+ public Optional<TreeNode> storeSnapshot(final Optional<TreeNode> snapshot) {
+ snapshotCache = snapshot;
+ return snapshot;
+ }
+
+ public Optional<Optional<TreeNode>> getSnapshotCache() {
+ return Optional.fromNullable(snapshotCache);
+ }
+
+ @GuardedBy("this")
+ private void updateModificationType(final ModificationType type) {
+ modificationType = type;
+ clearSnapshot();
+ }
+
+ @Override
+ public String toString() {
+ return "NodeModification [identifier=" + identifier + ", modificationType="
+ + modificationType + ", childModification=" + childModification + "]";
+ }
+
+ public static ModifiedNode createUnmodified(final TreeNode metadataTree) {
+ return new ModifiedNode(metadataTree.getIdentifier(), Optional.of(metadataTree));
+ }
+}
*/
package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.annotation.concurrent.GuardedBy;
-
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-
-/**
- * Node Modification Node and Tree
- *
- * Tree which structurally resembles data tree and captures client modifications
- * to the data store tree.
- *
- * This tree is lazily created and populated via {@link #modifyChild(PathArgument)}
- * and {@link StoreMetadataNode} which represents original state {@link #getOriginal()}.
- */
-final class NodeModification implements StoreTreeNode<NodeModification>, Identifiable<PathArgument> {
-
- public static final Predicate<NodeModification> IS_TERMINAL_PREDICATE = new Predicate<NodeModification>() {
- @Override
- public boolean apply(final NodeModification input) {
- return input.getModificationType() == ModificationType.WRITE //
- || input.getModificationType() == ModificationType.DELETE //
- || input.getModificationType() == ModificationType.MERGE;
- }
- };
- private final PathArgument identifier;
- private ModificationType modificationType = ModificationType.UNMODIFIED;
-
-
- private final Optional<StoreMetadataNode> original;
-
- private NormalizedNode<?, ?> value;
-
- private Optional<StoreMetadataNode> snapshotCache;
-
- private final Map<PathArgument, NodeModification> childModification;
-
- @GuardedBy("this")
- private boolean sealed = false;
-
- protected NodeModification(final PathArgument identifier, final Optional<StoreMetadataNode> original) {
- this.identifier = identifier;
- this.original = original;
- childModification = new LinkedHashMap<>();
- }
-
- /**
- *
- *
- * @return
- */
- public NormalizedNode<?, ?> getWrittenValue() {
- return value;
- }
-
- @Override
- public PathArgument getIdentifier() {
- return identifier;
- }
-
- /**
- *
- * Returns original store metadata
- * @return original store metadata
- */
- public final Optional<StoreMetadataNode> getOriginal() {
- return original;
- }
-
- /**
- * Returns modification type
- *
- * @return modification type
- */
- public final ModificationType getModificationType() {
- return modificationType;
- }
-
- /**
- *
- * Returns child modification if child was modified
- *
- * @return Child modification if direct child or it's subtree
- * was modified.
- *
- */
- @Override
- public Optional<NodeModification> getChild(final PathArgument child) {
- return Optional.<NodeModification> fromNullable(childModification.get(child));
- }
-
- /**
- *
- * Returns child modification if child was modified, creates {@link NodeModification}
- * for child otherwise.
- *
- * If this node's {@link ModificationType} is {@link ModificationType#UNMODIFIED}
- * changes modification type to {@link ModificationType#SUBTREE_MODIFIED}
- *
- * @param child
- * @return {@link NodeModification} for specified child, with {@link #getOriginal()}
- * containing child metadata if child was present in original data.
- */
- public synchronized NodeModification modifyChild(final PathArgument child) {
- checkSealed();
- clearSnapshot();
- if(modificationType == ModificationType.UNMODIFIED) {
- updateModificationType(ModificationType.SUBTREE_MODIFIED);
- }
- final NodeModification potential = childModification.get(child);
- if (potential != null) {
- return potential;
- }
- Optional<StoreMetadataNode> currentMetadata = Optional.absent();
- if(original.isPresent()) {
- currentMetadata = original.get().getChild(child);
- }
- NodeModification newlyCreated = new NodeModification(child,currentMetadata);
- childModification.put(child, newlyCreated);
- return newlyCreated;
- }
-
- /**
- *
- * Returns all recorded direct child modification
- *
- * @return all recorded direct child modifications
- */
- public Iterable<NodeModification> getModifications() {
- return childModification.values();
- }
-
-
- /**
- *
- * Records a delete for associated node.
- *
- */
- public synchronized void delete() {
- checkSealed();
- clearSnapshot();
- updateModificationType(ModificationType.DELETE);
- childModification.clear();
- this.value = null;
- }
-
- /**
- *
- * Records a write for associated node.
- *
- * @param value
- */
- public synchronized void write(final NormalizedNode<?, ?> value) {
- checkSealed();
- clearSnapshot();
- updateModificationType(ModificationType.WRITE);
- childModification.clear();
- this.value = value;
- }
-
- public synchronized void merge(final NormalizedNode<?, ?> data) {
- checkSealed();
- clearSnapshot();
- updateModificationType(ModificationType.MERGE);
- // FIXME: Probably merge with previous value.
- this.value = data;
- }
-
- @GuardedBy("this")
- private void checkSealed() {
- Preconditions.checkState(!sealed, "Node Modification is sealed. No further changes allowed.");
- }
-
- public synchronized void seal() {
- sealed = true;
- clearSnapshot();
- for(NodeModification child : childModification.values()) {
- child.seal();
- }
- }
-
- private void clearSnapshot() {
- snapshotCache = null;
- }
-
- public Optional<StoreMetadataNode> storeSnapshot(final Optional<StoreMetadataNode> snapshot) {
- snapshotCache = snapshot;
- return snapshot;
- }
-
- public Optional<Optional<StoreMetadataNode>> getSnapshotCache() {
- return Optional.fromNullable(snapshotCache);
- }
-
- public boolean hasAdditionalModifications() {
- return !childModification.isEmpty();
- }
-
- @GuardedBy("this")
- private void updateModificationType(final ModificationType type) {
- modificationType = type;
- clearSnapshot();
- }
-
- @Override
- public String toString() {
- return "NodeModification [identifier=" + identifier + ", modificationType="
- + modificationType + ", childModification=" + childModification + "]";
- }
-
- public static NodeModification createUnmodified(final StoreMetadataNode metadataTree) {
- return new NodeModification(metadataTree.getIdentifier(), Optional.of(metadataTree));
- }
+interface NodeModification extends Identifiable<PathArgument> {
+ ModificationType getType();
+ Optional<TreeNode> getOriginal();
+ Iterable<? extends NodeModification> getChildren();
}
}
};
- protected NoopDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot) {
+ protected NoopDataTreeCandidate(final InstanceIdentifier rootPath, final ModifiedNode modificationRoot) {
super(rootPath);
- Preconditions.checkArgument(modificationRoot.getModificationType() == ModificationType.UNMODIFIED);
+ Preconditions.checkArgument(modificationRoot.getType() == ModificationType.UNMODIFIED);
}
@Override
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.DataNodeContainerModificationStrategy.ListEntryModificationStrategy;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ValueNodeModificationStrategy.LeafSetEntryModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.MutableTreeNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNodeFactory;
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 com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
import com.google.common.primitives.UnsignedLong;
abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation {
}
@Override
- public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
- if (modification.getModificationType() == ModificationType.WRITE) {
+ public void verifyStructure(final ModifiedNode modification) throws IllegalArgumentException {
+ if (modification.getType() == ModificationType.WRITE) {
}
- for (NodeModification childModification : modification.getModifications()) {
+ for (ModifiedNode childModification : modification.getChildren()) {
resolveChildOperation(childModification.getIdentifier()).verifyStructure(childModification);
}
}
@Override
protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ final Optional<TreeNode> current) throws DataPreconditionFailedException {
// 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.
}
@Override
- protected StoreMetadataNode applyWrite(final NodeModification modification,
- final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
-
- NormalizedNode<?, ?> newValue = modification.getWrittenValue();
-
+ protected TreeNode applyWrite(final ModifiedNode modification,
+ final Optional<TreeNode> currentMeta, final UnsignedLong subtreeVersion) {
final UnsignedLong nodeVersion;
if (currentMeta.isPresent()) {
- nodeVersion = StoreUtils.increase(currentMeta.get().getNodeVersion());
+ nodeVersion = StoreUtils.increase(currentMeta.get().getVersion());
} else {
nodeVersion = subtreeVersion;
}
- final StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion);
- if (!modification.hasAdditionalModifications()) {
+ final NormalizedNode<?, ?> newValue = modification.getWrittenValue();
+ final TreeNode newValueMeta = TreeNodeFactory.createTreeNode(newValue, nodeVersion);
+
+ if (Iterables.isEmpty(modification.getChildren())) {
return newValueMeta;
}
+ /*
+ * This is where things get interesting. The user has performed a write and
+ * then she applied some more modifications to it. So we need to make sense
+ * of that an apply the operations on top of the written value. We could have
+ * done it during the write, but this operation is potentially expensive, so
+ * we have left it out of the fast path.
+ *
+ * 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.
+ */
+ final MutableTreeNode mutable = newValueMeta.mutable();
+ mutable.setSubtreeVersion(subtreeVersion);
+
@SuppressWarnings("rawtypes")
- NormalizedNodeContainerBuilder dataBuilder = createBuilder(newValue);
- StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.create(nodeVersion, dataBuilder) //
- .setSubtreeVersion(subtreeVersion);
+ final NormalizedNodeContainerBuilder dataBuilder = createBuilder(newValue);
+
+ return mutateChildren(mutable, dataBuilder, nodeVersion, modification.getChildren());
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private TreeNode mutateChildren(final MutableTreeNode meta, final NormalizedNodeContainerBuilder data,
+ final UnsignedLong nodeVersion, final Iterable<ModifiedNode> modifications) {
+
+ for (ModifiedNode mod : modifications) {
+ final PathArgument id = mod.getIdentifier();
+ final Optional<TreeNode> cm = meta.getChild(id);
+
+ Optional<TreeNode> result = resolveChildOperation(id).apply(mod, cm, nodeVersion);
+ if (result.isPresent()) {
+ final TreeNode tn = result.get();
+ meta.addChild(tn);
+ data.addChild(tn.getData());
+ } else {
+ meta.removeChild(id);
+ data.removeChild(id);
+ }
+ }
- return mutateChildren(modification.getModifications(), newValueMeta, builder, nodeVersion);
+ meta.setData(data.build());
+ return meta.seal();
}
@Override
- protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
+ protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta,
final UnsignedLong subtreeVersion) {
// For Node Containers - merge is same as subtree change - we only replace children.
return applySubtreeChange(modification, currentMeta, subtreeVersion);
}
@Override
- public StoreMetadataNode applySubtreeChange(final NodeModification modification,
- final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
+ public TreeNode applySubtreeChange(final ModifiedNode modification,
+ final TreeNode currentMeta, final UnsignedLong subtreeVersion) {
// Bump subtree version to its new target
final UnsignedLong updatedSubtreeVersion = StoreUtils.increase(currentMeta.getSubtreeVersion());
+ final MutableTreeNode newMeta = currentMeta.mutable();
+ newMeta.setSubtreeVersion(updatedSubtreeVersion);
+
@SuppressWarnings("rawtypes")
NormalizedNodeContainerBuilder dataBuilder = createBuilder(currentMeta.getData());
- StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.create(dataBuilder, currentMeta)
- .setIdentifier(modification.getIdentifier())
- .setSubtreeVersion(updatedSubtreeVersion);
- return mutateChildren(modification.getModifications(), currentMeta, builder, updatedSubtreeVersion);
- }
-
- private StoreMetadataNode mutateChildren(final Iterable<NodeModification> modifications, final StoreMetadataNode meta,
- final StoreNodeCompositeBuilder builder, final UnsignedLong nodeVersion) {
-
- for (NodeModification mod : modifications) {
- final PathArgument id = mod.getIdentifier();
- final Optional<StoreMetadataNode> cm = meta.getChild(id);
-
- Optional<StoreMetadataNode> result = resolveChildOperation(id).apply(mod, cm, nodeVersion);
- if (result.isPresent()) {
- builder.add(result.get());
- } else {
- builder.remove(id);
- }
- }
-
- return builder.build();
+ return mutateChildren(newMeta, dataBuilder, updatedSubtreeVersion, modification.getChildren());
}
@Override
- protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification,
+ final Optional<TreeNode> current) throws DataPreconditionFailedException {
checkDataPrecondition(path, current.isPresent(), "Node was deleted by other transaction.");
- checkChildPreconditions(path,modification,current);
-
+ checkChildPreconditions(path, modification, current);
}
- private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
- StoreMetadataNode currentMeta = current.get();
- for (NodeModification childMod : modification.getModifications()) {
- PathArgument childId = childMod.getIdentifier();
- Optional<StoreMetadataNode> childMeta = currentMeta.getChild(childId);
+ private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataPreconditionFailedException {
+ final TreeNode currentMeta = current.get();
+ for (NodeModification childMod : modification.getChildren()) {
+ final PathArgument childId = childMod.getIdentifier();
+ final Optional<TreeNode> childMeta = currentMeta.getChild(childId);
+
InstanceIdentifier childPath = StoreUtils.append(path, childId);
- resolveChildOperation(childId).checkApplicable(childPath,childMod, childMeta);
+ resolveChildOperation(childId).checkApplicable(childPath, childMod, childMeta);
}
}
@Override
protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ final Optional<TreeNode> current) throws DataPreconditionFailedException {
if(current.isPresent()) {
- checkChildPreconditions(path,modification,current);
+ checkChildPreconditions(path, modification,current);
}
}
return "UnorderedMapModificationStrategy [entry=" + entryStrategy + "]";
}
}
-}
\ No newline at end of file
+}
*/
package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
final class OperationWithModification {
- private final NodeModification modification;
+ private final ModifiedNode modification;
private final ModificationApplyOperation applyOperation;
- private OperationWithModification(final ModificationApplyOperation op, final NodeModification mod) {
+ private OperationWithModification(final ModificationApplyOperation op, final ModifiedNode mod) {
this.modification = mod;
this.applyOperation = op;
}
return this;
}
- public NodeModification getModification() {
+ public ModifiedNode getModification() {
return modification;
}
return applyOperation;
}
- public Optional<StoreMetadataNode> apply(final Optional<StoreMetadataNode> data, final UnsignedLong subtreeVersion) {
+ public Optional<TreeNode> apply(final Optional<TreeNode> data, final UnsignedLong subtreeVersion) {
return applyOperation.apply(modification, data, subtreeVersion);
}
public static OperationWithModification from(final ModificationApplyOperation operation,
- final NodeModification modification) {
+ final ModifiedNode modification) {
return new OperationWithModification(operation, modification);
}
}
public OperationWithModification forChild(final PathArgument childId) {
- NodeModification childMod = modification.modifyChild(childId);
+ ModifiedNode childMod = modification.modifyChild(childId);
Optional<ModificationApplyOperation> childOp = applyOperation.getChild(childId);
return from(childOp.get(),childMod);
}
import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.OrderedMapModificationStrategy;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.UnorderedLeafSetModificationStrategy;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ValueNodeModificationStrategy.LeafModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNodeFactory;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
return null;
}
+ public static boolean checkDataPrecondition(final InstanceIdentifier path, final boolean condition, final String message) throws DataPreconditionFailedException {
+ if(!condition) {
+ throw new DataPreconditionFailedException(path, message);
+ }
+ return condition;
+ }
+
private static SchemaAwareApplyOperation fromListSchemaNode(final ListSchemaNode schemaNode) {
List<QName> keyDefinition = schemaNode.getKeyDefinition();
if (keyDefinition == null || keyDefinition.isEmpty()) {
}
}
- private static final void checkNotConflicting(final InstanceIdentifier path,final StoreMetadataNode original, final StoreMetadataNode current) throws DataPreconditionFailedException {
- checkDataPrecondition(path, original.getNodeVersion().equals(current.getNodeVersion()),"Node was replaced by other transaction.");
- checkDataPrecondition(path,original.getSubtreeVersion().equals(current.getSubtreeVersion()), "Node children was modified by other transaction");
+ private static final void checkNotConflicting(final InstanceIdentifier path, final TreeNode original, final TreeNode current) throws DataPreconditionFailedException {
+ checkDataPrecondition(path, original.getVersion().equals(current.getVersion()),
+ "Node was replaced by other transaction.");
+ checkDataPrecondition(path, original.getSubtreeVersion().equals(current.getSubtreeVersion()),
+ "Node children was modified by other transaction");
}
protected final ModificationApplyOperation resolveChildOperation(final PathArgument child) {
}
@Override
- public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
- if (modification.getModificationType() == ModificationType.WRITE) {
+ public void verifyStructure(final ModifiedNode modification) throws IllegalArgumentException {
+ if (modification.getType() == ModificationType.WRITE) {
verifyWrittenStructure(modification.getWrittenValue());
}
}
@Override
- public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
- switch (modification.getModificationType()) {
+ public final void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<TreeNode> current) throws DataPreconditionFailedException {
+ switch (modification.getType()) {
case DELETE:
checkDeleteApplicable(modification, current);
case SUBTREE_MODIFIED:
- checkSubtreeModificationApplicable(path,modification, current);
+ checkSubtreeModificationApplicable(path, modification, current);
return;
case WRITE:
- checkWriteApplicable(path,modification, current);
+ checkWriteApplicable(path, modification, current);
return;
case MERGE:
- checkMergeApplicable(path,modification,current);
+ checkMergeApplicable(path, modification, current);
return;
case UNMODIFIED:
return;
default:
- throw new UnsupportedOperationException("Suplied modification type "+modification.getModificationType()+ "is not supported.");
+ throw new UnsupportedOperationException("Suplied modification type "+ modification.getType()+ "is not supported.");
}
}
- protected void checkMergeApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
- Optional<StoreMetadataNode> original = modification.getOriginal();
+ protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataPreconditionFailedException {
+ Optional<TreeNode> original = modification.getOriginal();
if (original.isPresent() && current.isPresent()) {
/*
* We need to do conflict detection only and only if the value of leaf changed
* leads to same data.
*/
if(!original.get().getData().equals(current.get().getData())) {
-
- checkNotConflicting(path,original.get(), current.get());
+ checkNotConflicting(path, original.get(), current.get());
}
}
}
- protected void checkWriteApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
- Optional<StoreMetadataNode> original = modification.getOriginal();
+ protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataPreconditionFailedException {
+ Optional<TreeNode> original = modification.getOriginal();
if (original.isPresent() && current.isPresent()) {
- checkNotConflicting(path,original.get(), current.get());
+ checkNotConflicting(path, original.get(), current.get());
} else if(original.isPresent()) {
throw new DataPreconditionFailedException(path,"Node was deleted by other transaction.");
}
}
- private void checkDeleteApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
+ private void checkDeleteApplicable(final NodeModification modification, final Optional<TreeNode> current) {
// Delete is always applicable, we do not expose it to subclasses
if (current.isPresent()) {
LOG.trace("Delete operation turned to no-op on missing node {}", modification);
}
@Override
- public final Optional<StoreMetadataNode> apply(final NodeModification modification,
- final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
+ public final Optional<TreeNode> apply(final ModifiedNode modification,
+ final Optional<TreeNode> currentMeta, final UnsignedLong subtreeVersion) {
- switch (modification.getModificationType()) {
+ switch (modification.getType()) {
case DELETE:
- return modification.storeSnapshot(Optional.<StoreMetadataNode> absent());
+ return modification.storeSnapshot(Optional.<TreeNode> absent());
case SUBTREE_MODIFIED:
Preconditions.checkArgument(currentMeta.isPresent(), "Metadata not available for modification",
modification);
}
}
- protected abstract StoreMetadataNode applyMerge(NodeModification modification,
- StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
+ protected abstract TreeNode applyMerge(ModifiedNode modification,
+ TreeNode currentMeta, UnsignedLong subtreeVersion);
- protected abstract StoreMetadataNode applyWrite(NodeModification modification,
- Optional<StoreMetadataNode> currentMeta, UnsignedLong subtreeVersion);
+ protected abstract TreeNode applyWrite(ModifiedNode modification,
+ Optional<TreeNode> currentMeta, UnsignedLong subtreeVersion);
- protected abstract StoreMetadataNode applySubtreeChange(NodeModification modification,
- StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
+ protected abstract TreeNode applySubtreeChange(ModifiedNode modification,
+ TreeNode currentMeta, UnsignedLong subtreeVersion);
- protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path,final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
+ protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path, final NodeModification modification,
+ final Optional<TreeNode> current) throws DataPreconditionFailedException;
protected abstract void verifyWrittenStructure(NormalizedNode<?, ?> writtenValue);
}
@Override
- protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
+ protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta,
final UnsignedLong subtreeVersion) {
return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
}
@Override
- protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
- final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
+ protected TreeNode applySubtreeChange(final ModifiedNode modification,
+ final TreeNode currentMeta, final UnsignedLong subtreeVersion) {
throw new UnsupportedOperationException("UnkeyedList does not support subtree change.");
}
@Override
- protected StoreMetadataNode applyWrite(final NodeModification modification,
- final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
- return StoreMetadataNode.createRecursively(modification.getWrittenValue(), subtreeVersion);
+ protected TreeNode applyWrite(final ModifiedNode modification,
+ final Optional<TreeNode> currentMeta, final UnsignedLong subtreeVersion) {
+ return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), subtreeVersion);
}
@Override
}
@Override
- protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification,
+ final Optional<TreeNode> current) throws DataPreconditionFailedException {
throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
}
}
-
- public static boolean checkDataPrecondition(final InstanceIdentifier path, final boolean condition, final String message) throws DataPreconditionFailedException {
- if(!condition) {
- throw new DataPreconditionFailedException(path, message);
- }
- return condition;
- }
-
}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
-
-import static com.google.common.base.Preconditions.checkState;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.opendaylight.yangtools.concepts.Identifiable;
-import org.opendaylight.yangtools.concepts.Immutable;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.primitives.UnsignedLong;
-
-class StoreMetadataNode implements Immutable, Identifiable<PathArgument> {
- private final Map<PathArgument, StoreMetadataNode> children;
- private final UnsignedLong nodeVersion;
- private final UnsignedLong subtreeVersion;
- private final NormalizedNode<?, ?> data;
-
- /**
- *
- * @param data
- * @param nodeVersion
- * @param subtreeVersion
- * @param children Map of children, must not be modified externally
- */
- private StoreMetadataNode(final NormalizedNode<?, ?> data, final UnsignedLong nodeVersion,
- final UnsignedLong subtreeVersion, final Map<PathArgument, StoreMetadataNode> children) {
- this.nodeVersion = Preconditions.checkNotNull(nodeVersion);
- this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion);
- this.data = Preconditions.checkNotNull(data);
- this.children = Preconditions.checkNotNull(children);
- }
-
- public static StoreMetadataNode createEmpty(final NormalizedNode<?, ?> data) {
- return new StoreMetadataNode(data, UnsignedLong.ZERO, UnsignedLong.ZERO,
- Collections.<PathArgument, StoreMetadataNode>emptyMap());
- }
-
- public static Builder builder(final UnsignedLong version) {
- return new Builder(version);
- }
-
- public static Builder builder(final StoreMetadataNode node) {
- return new Builder(node);
- }
-
- public UnsignedLong getNodeVersion() {
- return this.nodeVersion;
- }
-
- @Override
- public PathArgument getIdentifier() {
- return data.getIdentifier();
- }
-
- public UnsignedLong getSubtreeVersion() {
- return subtreeVersion;
- }
-
- public NormalizedNode<?, ?> getData() {
- return this.data;
- }
-
- Optional<StoreMetadataNode> getChild(final PathArgument key) {
- return Optional.fromNullable(children.get(key));
- }
-
- @Override
- public String toString() {
- return "StoreMetadataNode [identifier=" + getIdentifier() + ", nodeVersion=" + nodeVersion + "]";
- }
-
- public static final StoreMetadataNode createRecursively(final NormalizedNode<?, ?> node,
- final UnsignedLong version) {
- Builder builder = builder(version) //
- .setSubtreeVersion(version) //
- .setData(node);
- if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
-
- @SuppressWarnings("unchecked")
- NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> nodeContainer = (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) node;
- for (NormalizedNode<?, ?> subNode : nodeContainer.getValue()) {
- builder.add(createRecursively(subNode, version));
- }
- }
- return builder.build();
- }
-
- public static class Builder {
-
- private final UnsignedLong nodeVersion;
- private UnsignedLong subtreeVersion;
- private NormalizedNode<?, ?> data;
- private Map<PathArgument, StoreMetadataNode> children;
- private boolean dirty = false;
-
- private Builder(final UnsignedLong version) {
- this.nodeVersion = Preconditions.checkNotNull(version);
- children = new HashMap<>();
- }
-
- private Builder(final StoreMetadataNode node) {
- this.nodeVersion = node.getNodeVersion();
- children = new HashMap<>(node.children);
- }
-
- public Builder setSubtreeVersion(final UnsignedLong version) {
- this.subtreeVersion = version;
- return this;
- }
-
- public Builder setData(final NormalizedNode<?, ?> data) {
- this.data = data;
- return this;
- }
-
- public Builder add(final StoreMetadataNode node) {
- if (dirty) {
- children = new HashMap<>(children);
- dirty = false;
- }
- children.put(node.getIdentifier(), node);
- return this;
- }
-
- public Builder remove(final PathArgument id) {
- if (dirty) {
- children = new HashMap<>(children);
- dirty = false;
- }
- children.remove(id);
- return this;
- }
-
- public StoreMetadataNode build() {
- checkState(data != null, "Data node should not be null.");
- checkState(subtreeVersion.compareTo(nodeVersion) >= 0,
- "Subtree version must be equals or greater than node version.");
- dirty = true;
- return new StoreMetadataNode(data, nodeVersion, subtreeVersion, children);
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
-
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
-
-import com.google.common.base.Preconditions;
-import com.google.common.primitives.UnsignedLong;
-
-/**
- *
- * Helper builder
- *
- *
- */
-@SuppressWarnings("rawtypes")
-class StoreNodeCompositeBuilder {
-
- private final StoreMetadataNode.Builder metadata;
-
- private final NormalizedNodeContainerBuilder data;
-
- private StoreNodeCompositeBuilder(final UnsignedLong version, final NormalizedNodeContainerBuilder nodeBuilder) {
- this.metadata = StoreMetadataNode.builder(version);
- this.data = Preconditions.checkNotNull(nodeBuilder);
- }
-
- private StoreNodeCompositeBuilder(final NormalizedNodeContainerBuilder nodeBuilder, final StoreMetadataNode currentMeta) {
- this.metadata = StoreMetadataNode.builder(currentMeta);
- this.data = Preconditions.checkNotNull(nodeBuilder);
- }
-
- @SuppressWarnings("unchecked")
- public StoreNodeCompositeBuilder add(final StoreMetadataNode node) {
- metadata.add(node);
- data.addChild(node.getData());
- return this;
- }
-
- @SuppressWarnings("unchecked")
- public StoreNodeCompositeBuilder remove(final PathArgument id) {
- metadata.remove(id);
- data.removeChild(id);
- return this;
- }
-
- public StoreMetadataNode build() {
- return metadata.setData(data.build()).build();
- }
-
- public static StoreNodeCompositeBuilder create(final UnsignedLong version, final NormalizedNodeContainerBuilder nodeBuilder) {
- return new StoreNodeCompositeBuilder(version, nodeBuilder);
- }
-
- public static StoreNodeCompositeBuilder create(final NormalizedNodeContainerBuilder nodeBuilder, final StoreMetadataNode currentMeta) {
- return new StoreNodeCompositeBuilder(nodeBuilder, currentMeta);
- }
-
- @SuppressWarnings("unchecked")
- public StoreNodeCompositeBuilder setIdentifier(final PathArgument identifier) {
- data.withNodeIdentifier(identifier);
- return this;
- }
-
- public StoreNodeCompositeBuilder setSubtreeVersion(final UnsignedLong updatedSubtreeVersion) {
- metadata.setSubtreeVersion(updatedSubtreeVersion);
- return this;
- }
-}
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
- */package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
+ */
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
- import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkArgument;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
- import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
- import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
- import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
- import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
- import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
- import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
- import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
- import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNodeFactory;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import com.google.common.base.Optional;
- import com.google.common.primitives.UnsignedLong;
+import com.google.common.primitives.UnsignedLong;
- abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends SchemaAwareApplyOperation {
+abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends SchemaAwareApplyOperation {
- private final T schema;
- private final Class<? extends NormalizedNode<?, ?>> nodeClass;
+ private final T schema;
+ private final Class<? extends NormalizedNode<?, ?>> nodeClass;
- protected ValueNodeModificationStrategy(final T schema, final Class<? extends NormalizedNode<?, ?>> nodeClass) {
- super();
- this.schema = schema;
- this.nodeClass = nodeClass;
- }
+ protected ValueNodeModificationStrategy(final T schema, final Class<? extends NormalizedNode<?, ?>> nodeClass) {
+ super();
+ this.schema = schema;
+ this.nodeClass = nodeClass;
+ }
- @Override
- protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
- checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
- }
+ @Override
+ protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
+ checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
+ }
- @Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
- throw new UnsupportedOperationException("Node " + schema.getPath()
- + "is leaf type node. Child nodes not allowed");
- }
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
+ throw new UnsupportedOperationException("Node " + schema.getPath()
+ + "is leaf type node. Child nodes not allowed");
+ }
- @Override
- protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
- final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
- throw new UnsupportedOperationException("Node " + schema.getPath()
- + "is leaf type node. Subtree change is not allowed.");
- }
+ @Override
+ protected TreeNode applySubtreeChange(final ModifiedNode modification,
+ final TreeNode currentMeta, final UnsignedLong subtreeVersion) {
+ throw new UnsupportedOperationException("Node " + schema.getPath()
+ + "is leaf type node. Subtree change is not allowed.");
+ }
- @Override
- protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
- final UnsignedLong subtreeVersion) {
- return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
- }
+ @Override
+ protected TreeNode applyMerge(final ModifiedNode modification, final TreeNode currentMeta,
+ final UnsignedLong subtreeVersion) {
+ // Just overwrite whatever was there
+ return applyWrite(modification, null, subtreeVersion);
+ }
- @Override
- protected StoreMetadataNode applyWrite(final NodeModification modification,
- final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
- return StoreMetadataNode.builder(subtreeVersion).setSubtreeVersion(subtreeVersion)
- .setData(modification.getWrittenValue()).build();
- }
+ @Override
+ protected TreeNode applyWrite(final ModifiedNode modification,
+ final Optional<TreeNode> currentMeta, final UnsignedLong subtreeVersion) {
+ return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), subtreeVersion);
+ }
- @Override
- protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
- throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
- }
+ @Override
+ protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification,
+ final Optional<TreeNode> current) throws DataPreconditionFailedException {
+ throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
+ }
- public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy<LeafListSchemaNode> {
- @SuppressWarnings({ "unchecked", "rawtypes" })
- protected LeafSetEntryModificationStrategy(final LeafListSchemaNode schema) {
- super(schema, (Class) LeafSetEntryNode.class);
- }
- }
+ public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy<LeafListSchemaNode> {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected LeafSetEntryModificationStrategy(final LeafListSchemaNode schema) {
+ super(schema, (Class) LeafSetEntryNode.class);
+ }
+ }
- public static class LeafModificationStrategy extends ValueNodeModificationStrategy<LeafSchemaNode> {
- @SuppressWarnings({ "unchecked", "rawtypes" })
- protected LeafModificationStrategy(final LeafSchemaNode schema) {
- super(schema, (Class) LeafNode.class);
- }
- }
- }
\ No newline at end of file
+ public static class LeafModificationStrategy extends ValueNodeModificationStrategy<LeafSchemaNode> {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected LeafModificationStrategy(final LeafSchemaNode schema) {
+ super(schema, (Class) LeafNode.class);
+ }
+ }
+}
\ No newline at end of file
import org.opendaylight.controller.md.sal.dom.store.impl.TestModel;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNodeFactory;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
@Test
public void basicReadWrites() {
DataTreeModification modificationTree = new InMemoryDataTreeModification(new InMemoryDataTreeSnapshot(schemaContext,
- StoreMetadataNode.createRecursively(createDocumentOne(), UnsignedLong.valueOf(5)), applyOper),
+ TreeNodeFactory.createTreeNode(createDocumentOne(), UnsignedLong.valueOf(5)), applyOper),
new SchemaAwareApplyOperationRoot(schemaContext));
Optional<NormalizedNode<?, ?>> originalBarNode = modificationTree.readNode(OUTER_LIST_2_PATH);
assertTrue(originalBarNode.isPresent());