From: Robert Varga Date: Thu, 22 May 2014 20:58:55 +0000 (+0200) Subject: BUG-509: migrate to TreeNodes X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~32^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=f2df8835acd421467dbf5adaf1aa71609eac1512 BUG-509: migrate to TreeNodes This patch performs the switchover to SPI-provided TreeNodes. It also extracts the information needed for checking applicability of a modification into a separate interface. Also adds some documentation in the non-trivial write+merge path. Change-Id: I83f5ca30bff21774759f9b675b19b6e9622076a2 Signed-off-by: Robert Varga --- diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/AlwaysFailOperation.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/AlwaysFailOperation.java index 5934fd6246..7f66f7ff7e 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/AlwaysFailOperation.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/AlwaysFailOperation.java @@ -1,5 +1,6 @@ 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; @@ -14,13 +15,13 @@ import com.google.common.primitives.UnsignedLong; */ final class AlwaysFailOperation implements ModificationApplyOperation { @Override - public Optional apply(final NodeModification modification, - final Optional storeMeta, final UnsignedLong subtreeVersion) { + public Optional apply(final ModifiedNode modification, + final Optional storeMeta, final UnsignedLong subtreeVersion) { throw new IllegalStateException("Schema Context is not available."); } @Override - public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional storeMetadata) { + public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional storeMetadata) { throw new IllegalStateException("Schema Context is not available."); } @@ -30,7 +31,7 @@ final class AlwaysFailOperation implements ModificationApplyOperation { } @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 diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTree.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTree.java index f04e379dd9..ae71ed9adf 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTree.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTree.java @@ -16,6 +16,7 @@ import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate; 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; @@ -34,9 +35,9 @@ final class InMemoryDataTree implements DataTree { 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) { @@ -80,28 +81,27 @@ final class InMemoryDataTree implements DataTree { } @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.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 newRoot = m.getStrategy().apply(m.getRootModification(), Optional.of(rootNode), StoreUtils.increase(rootNode.getSubtreeVersion())); + final Optional newRoot = m.getStrategy().apply(m.getRootModification(), Optional.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 { @@ -110,7 +110,7 @@ final class InMemoryDataTree implements DataTree { } @Override - public synchronized void commit(DataTreeCandidate candidate) { + public synchronized void commit(final DataTreeCandidate candidate) { if (candidate instanceof NoopDataTreeCandidate) { return; } @@ -118,7 +118,7 @@ final class InMemoryDataTree implements DataTree { 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())); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeCandidate.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeCandidate.java index 72562f0a72..bafea6bd97 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeCandidate.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeCandidate.java @@ -2,6 +2,7 @@ package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; 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; @@ -13,38 +14,42 @@ import com.google.common.collect.Iterables; 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 getChildNodes() { - return Iterables.transform(mod.getModifications(), new Function() { + return Iterables.transform(mod.getChildren(), new Function() { @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)); } @@ -53,14 +58,15 @@ final class InMemoryDataTreeCandidate extends AbstractDataTreeCandidate { @Override public ModificationType getModificationType() { - return mod.getModificationType(); + return mod.getType(); } - private Optional> optionalData(StoreMetadataNode meta) { - if (meta == null) { + private Optional> optionalData(final TreeNode meta) { + if (meta != null) { + return Optional.>of(meta.getData()); + } else { return Optional.absent(); } - return Optional.>of(meta.getData()); } @Override @@ -75,7 +81,7 @@ final class InMemoryDataTreeCandidate extends AbstractDataTreeCandidate { } 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); } @@ -86,7 +92,7 @@ final class InMemoryDataTreeCandidate extends AbstractDataTreeCandidate { } 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); } @@ -98,17 +104,17 @@ final class InMemoryDataTreeCandidate extends AbstractDataTreeCandidate { 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(); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeFactory.java index 7614611ab2..82ffad507d 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeFactory.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeFactory.java @@ -1,35 +1,38 @@ 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; + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java index 7d0c81e39d..fcb3ae0a10 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java @@ -15,6 +15,7 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; 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; @@ -39,15 +40,15 @@ final class InMemoryDataTreeModification implements DataTreeModification { 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; } @@ -93,11 +94,11 @@ final class InMemoryDataTreeModification implements DataTreeModification { * the requested path which has been modified. If no such node exists, * we use the node itself. */ - final Entry entry = TreeNodeUtils.findClosestsOrFirstMatch(rootNode, path, NodeModification.IS_TERMINAL_PREDICATE); + final Entry 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 result = resolveSnapshot(key, mod); + final Optional result = resolveSnapshot(key, mod); if (result.isPresent()) { NormalizedNode data = result.get().getData(); return NormalizedNodeUtils.findNode(key, data, path); @@ -106,9 +107,9 @@ final class InMemoryDataTreeModification implements DataTreeModification { } } - private Optional resolveSnapshot(final InstanceIdentifier path, - final NodeModification modification) { - final Optional> potentialSnapshot = modification.getSnapshotCache(); + private Optional resolveSnapshot(final InstanceIdentifier path, + final ModifiedNode modification) { + final Optional> potentialSnapshot = modification.getSnapshotCache(); if(potentialSnapshot.isPresent()) { return potentialSnapshot.get(); } @@ -128,7 +129,7 @@ final class InMemoryDataTreeModification implements DataTreeModification { } 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()) { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeSnapshot.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeSnapshot.java index ce2d8c9bd4..ee91e62518 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeSnapshot.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeSnapshot.java @@ -1,6 +1,7 @@ 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; @@ -12,16 +13,16 @@ import com.google.common.base.Preconditions; 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; } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationApplyOperation.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationApplyOperation.java index 5b4cd565e5..a72d4fb579 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationApplyOperation.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationApplyOperation.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; 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; @@ -17,7 +18,7 @@ import com.google.common.primitives.UnsignedLong; /** * - * 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 @@ -29,7 +30,7 @@ import com.google.common.primitives.UnsignedLong; * Implementations MUST expose all nested suboperations which operates on child * nodes expose via {@link #getChild(PathArgument)} method. *
  • 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 @@ -54,10 +55,10 @@ interface ModificationApplyOperation extends StoreTreeNode apply(NodeModification modification, Optional storeMeta, UnsignedLong subtreeVersion); + Optional apply(ModifiedNode modification, Optional storeMeta, UnsignedLong subtreeVersion); /** * @@ -67,7 +68,7 @@ interface ModificationApplyOperation extends StoreTreeNode current) throws DataPreconditionFailedException; + void checkApplicable(InstanceIdentifier path, NodeModification modification, Optional current) throws DataPreconditionFailedException; } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModifiedNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModifiedNode.java new file mode 100644 index 0000000000..0ff64e6a72 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModifiedNode.java @@ -0,0 +1,244 @@ +/* + * 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, Identifiable, NodeModification { + + public static final Predicate IS_TERMINAL_PREDICATE = new Predicate() { + @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 original; + + private NormalizedNode value; + + private Optional snapshotCache; + + private final Map childModification; + + @GuardedBy("this") + private boolean sealed = false; + + private ModifiedNode(final PathArgument identifier, final Optional 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 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 getChild(final PathArgument child) { + return Optional. 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 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 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 storeSnapshot(final Optional snapshot) { + snapshotCache = snapshot; + return snapshot; + } + + public Optional> 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)); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NodeModification.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NodeModification.java index fccc1ed5be..2639d050ef 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NodeModification.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NodeModification.java @@ -7,227 +7,15 @@ */ 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, Identifiable { - - public static final Predicate IS_TERMINAL_PREDICATE = new Predicate() { - @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 original; - - private NormalizedNode value; - - private Optional snapshotCache; - - private final Map childModification; - - @GuardedBy("this") - private boolean sealed = false; - - protected NodeModification(final PathArgument identifier, final Optional 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 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 getChild(final PathArgument child) { - return Optional. 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 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 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 storeSnapshot(final Optional snapshot) { - snapshotCache = snapshot; - return snapshot; - } - - public Optional> 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 { + ModificationType getType(); + Optional getOriginal(); + Iterable getChildren(); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NoopDataTreeCandidate.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NoopDataTreeCandidate.java index 8a46748414..2ef85cbcb7 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NoopDataTreeCandidate.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NoopDataTreeCandidate.java @@ -46,9 +46,9 @@ final class NoopDataTreeCandidate extends AbstractDataTreeCandidate { } }; - 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 diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NormalizedNodeContainerModificationStrategy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NormalizedNodeContainerModificationStrategy.java index 7ab840e0e0..c5037bc0c6 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NormalizedNodeContainerModificationStrategy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NormalizedNodeContainerModificationStrategy.java @@ -16,6 +16,9 @@ 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.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; @@ -42,6 +45,7 @@ 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; import com.google.common.primitives.UnsignedLong; abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation { @@ -53,18 +57,18 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp } @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 current) throws DataPreconditionFailedException { + final Optional 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. @@ -90,94 +94,110 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp } @Override - protected StoreMetadataNode applyWrite(final NodeModification modification, - final Optional currentMeta, final UnsignedLong subtreeVersion) { - - NormalizedNode newValue = modification.getWrittenValue(); - + protected TreeNode applyWrite(final ModifiedNode modification, + final Optional 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 modifications) { + + for (ModifiedNode mod : modifications) { + final PathArgument id = mod.getIdentifier(); + final Optional cm = meta.getChild(id); + + Optional 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 modifications, final StoreMetadataNode meta, - final StoreNodeCompositeBuilder builder, final UnsignedLong nodeVersion) { - - for (NodeModification mod : modifications) { - final PathArgument id = mod.getIdentifier(); - final Optional cm = meta.getChild(id); - - Optional 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 current) throws DataPreconditionFailedException { + protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification, + final Optional 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 current) throws DataPreconditionFailedException { - StoreMetadataNode currentMeta = current.get(); - for (NodeModification childMod : modification.getModifications()) { - PathArgument childId = childMod.getIdentifier(); - Optional childMeta = currentMeta.getChild(childId); + private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional current) throws DataPreconditionFailedException { + final TreeNode currentMeta = current.get(); + for (NodeModification childMod : modification.getChildren()) { + final PathArgument childId = childMod.getIdentifier(); + final Optional 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 current) throws DataPreconditionFailedException { + final Optional current) throws DataPreconditionFailedException { if(current.isPresent()) { - checkChildPreconditions(path,modification,current); + checkChildPreconditions(path, modification,current); } } @@ -325,4 +345,4 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp return "UnorderedMapModificationStrategy [entry=" + entryStrategy + "]"; } } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/OperationWithModification.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/OperationWithModification.java index fda8407a95..0a5fad3e8b 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/OperationWithModification.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/OperationWithModification.java @@ -7,6 +7,7 @@ */ 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; @@ -15,11 +16,11 @@ import com.google.common.primitives.UnsignedLong; 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; } @@ -35,7 +36,7 @@ final class OperationWithModification { return this; } - public NodeModification getModification() { + public ModifiedNode getModification() { return modification; } @@ -43,12 +44,12 @@ final class OperationWithModification { return applyOperation; } - public Optional apply(final Optional data, final UnsignedLong subtreeVersion) { + public Optional apply(final Optional 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); } @@ -60,7 +61,7 @@ final class OperationWithModification { } public OperationWithModification forChild(final PathArgument childId) { - NodeModification childMod = modification.modifyChild(childId); + ModifiedNode childMod = modification.modifyChild(childId); Optional childOp = applyOperation.getChild(childId); return from(childOp.get(),childMod); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/SchemaAwareApplyOperation.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/SchemaAwareApplyOperation.java index 7afc12caab..a0730e44da 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/SchemaAwareApplyOperation.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/SchemaAwareApplyOperation.java @@ -20,6 +20,8 @@ import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNod 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; @@ -80,6 +82,13 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { 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 keyDefinition = schemaNode.getKeyDefinition(); if (keyDefinition == null || keyDefinition.isEmpty()) { @@ -100,9 +109,11 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { } } - 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) { @@ -112,36 +123,36 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { } @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 current) throws DataPreconditionFailedException { - switch (modification.getModificationType()) { + public final void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional 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 current) throws DataPreconditionFailedException { - Optional original = modification.getOriginal(); + protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification, final Optional current) throws DataPreconditionFailedException { + Optional original = modification.getOriginal(); if (original.isPresent() && current.isPresent()) { /* * We need to do conflict detection only and only if the value of leaf changed @@ -150,22 +161,21 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { * 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 current) throws DataPreconditionFailedException { - Optional original = modification.getOriginal(); + protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification, final Optional current) throws DataPreconditionFailedException { + Optional 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 current) { + private void checkDeleteApplicable(final NodeModification modification, final Optional 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); @@ -173,12 +183,12 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { } @Override - public final Optional apply(final NodeModification modification, - final Optional currentMeta, final UnsignedLong subtreeVersion) { + public final Optional apply(final ModifiedNode modification, + final Optional currentMeta, final UnsignedLong subtreeVersion) { - switch (modification.getModificationType()) { + switch (modification.getType()) { case DELETE: - return modification.storeSnapshot(Optional. absent()); + return modification.storeSnapshot(Optional. absent()); case SUBTREE_MODIFIED: Preconditions.checkArgument(currentMeta.isPresent(), "Metadata not available for modification", modification); @@ -197,17 +207,17 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { } } - 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 currentMeta, UnsignedLong subtreeVersion); + protected abstract TreeNode applyWrite(ModifiedNode modification, + Optional 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 current) throws DataPreconditionFailedException; + protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path, final NodeModification modification, + final Optional current) throws DataPreconditionFailedException; protected abstract void verifyWrittenStructure(NormalizedNode writtenValue); @@ -220,21 +230,21 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { } @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 currentMeta, final UnsignedLong subtreeVersion) { - return StoreMetadataNode.createRecursively(modification.getWrittenValue(), subtreeVersion); + protected TreeNode applyWrite(final ModifiedNode modification, + final Optional currentMeta, final UnsignedLong subtreeVersion) { + return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), subtreeVersion); } @Override @@ -251,17 +261,9 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation { } @Override - protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification, - final Optional current) throws DataPreconditionFailedException { + protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification, + final Optional 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; - } - } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreMetadataNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreMetadataNode.java deleted file mode 100644 index 695a1f1dd3..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreMetadataNode.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 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 { - private final Map 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 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.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 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> nodeContainer = (NormalizedNodeContainer>) 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 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); - } - } - -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreNodeCompositeBuilder.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreNodeCompositeBuilder.java deleted file mode 100644 index 19debbb990..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreNodeCompositeBuilder.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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; - } -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ValueNodeModificationStrategy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ValueNodeModificationStrategy.java index 2892953935..6250b30702 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ValueNodeModificationStrategy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ValueNodeModificationStrategy.java @@ -4,82 +4,85 @@ * 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 extends SchemaAwareApplyOperation { +abstract class ValueNodeModificationStrategy extends SchemaAwareApplyOperation { - private final T schema; - private final Class> nodeClass; + private final T schema; + private final Class> nodeClass; - protected ValueNodeModificationStrategy(final T schema, final Class> nodeClass) { - super(); - this.schema = schema; - this.nodeClass = nodeClass; - } + protected ValueNodeModificationStrategy(final T schema, final Class> 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 getChild(final PathArgument child) { - throw new UnsupportedOperationException("Node " + schema.getPath() - + "is leaf type node. Child nodes not allowed"); - } + @Override + public Optional 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 currentMeta, final UnsignedLong subtreeVersion) { - return StoreMetadataNode.builder(subtreeVersion).setSubtreeVersion(subtreeVersion) - .setData(modification.getWrittenValue()).build(); - } + @Override + protected TreeNode applyWrite(final ModifiedNode modification, + final Optional currentMeta, final UnsignedLong subtreeVersion) { + return TreeNodeFactory.createTreeNode(modification.getWrittenValue(), subtreeVersion); + } - @Override - protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification, - final Optional current) throws DataPreconditionFailedException { - throw new DataPreconditionFailedException(path, "Subtree modification is not allowed."); - } + @Override + protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + throw new DataPreconditionFailedException(path, "Subtree modification is not allowed."); + } - public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy { - @SuppressWarnings({ "unchecked", "rawtypes" }) - protected LeafSetEntryModificationStrategy(final LeafListSchemaNode schema) { - super(schema, (Class) LeafSetEntryNode.class); - } - } + public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy { + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected LeafSetEntryModificationStrategy(final LeafListSchemaNode schema) { + super(schema, (Class) LeafSetEntryNode.class); + } + } - public static class LeafModificationStrategy extends ValueNodeModificationStrategy { - @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 { + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected LeafModificationStrategy(final LeafSchemaNode schema) { + super(schema, (Class) LeafNode.class); + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationMetadataTreeTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationMetadataTreeTest.java index 8940e55d32..abaa4d1eca 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationMetadataTreeTest.java +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationMetadataTreeTest.java @@ -29,6 +29,7 @@ import org.junit.Test; 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; @@ -149,7 +150,7 @@ public class ModificationMetadataTreeTest { @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> originalBarNode = modificationTree.readNode(OUTER_LIST_2_PATH); assertTrue(originalBarNode.isPresent());