X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-data-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Fimpl%2Fschema%2Ftree%2FInMemoryDataTreeModification.java;h=f91873bd4848e4674dfddd133a98f215b015d9c5;hb=a8a426a32c4df4f3f55a32dea7ee9b21721ca25e;hp=6ca6970637f249000a792bf796e4f635bd8dd531;hpb=adc2275288a6055dda77692b5a742835eb15af3b;p=yangtools.git diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java index 6ca6970637..f91873bd48 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java @@ -7,42 +7,47 @@ */ package org.opendaylight.yangtools.yang.data.impl.schema.tree; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.Iterables; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + import java.util.Collection; import java.util.Map.Entry; +import java.util.Optional; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; -import org.opendaylight.yangtools.yang.common.QName; +import javax.annotation.Nonnull; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; +import org.opendaylight.yangtools.yang.data.api.schema.tree.CursorAwareDataTreeModification; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModificationCursor; import org.opendaylight.yangtools.yang.data.api.schema.tree.StoreTreeNodes; import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -final class InMemoryDataTreeModification implements DataTreeModification { - private static final AtomicIntegerFieldUpdater UPDATER = +final class InMemoryDataTreeModification extends AbstractCursorAware implements CursorAwareDataTreeModification, + SchemaContextProvider { + private static final AtomicIntegerFieldUpdater SEALED_UPDATER = AtomicIntegerFieldUpdater.newUpdater(InMemoryDataTreeModification.class, "sealed"); private static final Logger LOG = LoggerFactory.getLogger(InMemoryDataTreeModification.class); - private final RootModificationApplyOperation strategyTree; + private final RootApplyStrategy strategyTree; private final InMemoryDataTreeSnapshot snapshot; private final ModifiedNode rootNode; private final Version version; private volatile int sealed = 0; - InMemoryDataTreeModification(final InMemoryDataTreeSnapshot snapshot, final RootModificationApplyOperation resolver) { - this.snapshot = Preconditions.checkNotNull(snapshot); - this.strategyTree = Preconditions.checkNotNull(resolver).snapshot(); - this.rootNode = ModifiedNode.createUnmodified(snapshot.getRootNode(), strategyTree.getChildPolicy()); + InMemoryDataTreeModification(final InMemoryDataTreeSnapshot snapshot, + final RootApplyStrategy resolver) { + this.snapshot = requireNonNull(snapshot); + this.strategyTree = requireNonNull(resolver).snapshot(); + this.rootNode = ModifiedNode.createUnmodified(snapshot.getRootNode(), getStrategy().getChildPolicy()); /* * We could allocate version beforehand, since Version contract @@ -61,7 +66,12 @@ final class InMemoryDataTreeModification implements DataTreeModification { } ModificationApplyOperation getStrategy() { - return strategyTree; + return strategyTree.delegate(); + } + + @Override + public SchemaContext getSchemaContext() { + return snapshot.getSchemaContext(); } @Override @@ -75,7 +85,7 @@ final class InMemoryDataTreeModification implements DataTreeModification { public void merge(final YangInstanceIdentifier path, final NormalizedNode data) { checkSealed(); checkIdentifierReferencesData(path, data); - resolveModificationFor(path).merge(data); + resolveModificationFor(path).merge(data, version); } @Override @@ -92,7 +102,8 @@ 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 = StoreTreeNodes.findClosestsOrFirstMatch(rootNode, path, ModifiedNode.IS_TERMINAL_PREDICATE); + final Entry entry = StoreTreeNodes.findClosestsOrFirstMatch(rootNode, + path, ModifiedNode.IS_TERMINAL_PREDICATE); final YangInstanceIdentifier key = entry.getKey(); final ModifiedNode mod = entry.getValue(); @@ -100,11 +111,12 @@ final class InMemoryDataTreeModification implements DataTreeModification { if (result.isPresent()) { final NormalizedNode data = result.get().getData(); return NormalizedNodes.findNode(key, data, path); - } else { - return Optional.absent(); } + + return Optional.empty(); } + @SuppressWarnings("checkstyle:illegalCatch") private Optional resolveSnapshot(final YangInstanceIdentifier path, final ModifiedNode modification) { final Optional potentialSnapshot = modification.getSnapshot(); if (potentialSnapshot != null) { @@ -112,15 +124,14 @@ final class InMemoryDataTreeModification implements DataTreeModification { } try { - return resolveModificationStrategy(path).apply(modification, modification.getOriginal(), - version); + return resolveModificationStrategy(path).apply(modification, modification.getOriginal(), version); } catch (final Exception e) { LOG.error("Could not create snapshot for {}:{}", path, modification, e); throw e; } } - private void upgradeIfPossible() { + void upgradeIfPossible() { if (rootNode.getOperation() == LogicalOperation.NONE) { strategyTree.upgradeIfPossible(); } @@ -130,7 +141,7 @@ final class InMemoryDataTreeModification implements DataTreeModification { LOG.trace("Resolving modification apply strategy for {}", path); upgradeIfPossible(); - return StoreTreeNodes.findNodeChecked(strategyTree, path); + return StoreTreeNodes.findNodeChecked(getStrategy(), path); } private OperationWithModification resolveModificationFor(final YangInstanceIdentifier path) { @@ -146,27 +157,27 @@ final class InMemoryDataTreeModification implements DataTreeModification { * That is fine, as we will prune any empty TOUCH nodes in the last phase of the ready * process. */ - ModificationApplyOperation operation = strategyTree; + ModificationApplyOperation operation = getStrategy(); ModifiedNode modification = rootNode; - int i = 1; - for(final PathArgument pathArg : path.getPathArguments()) { + int depth = 1; + for (final PathArgument pathArg : path.getPathArguments()) { final Optional potential = operation.getChild(pathArg); if (!potential.isPresent()) { throw new SchemaValidationFailedException(String.format("Child %s is not present in schema tree.", - Iterables.toString(Iterables.limit(path.getPathArguments(), i)))); + path.getAncestor(depth))); } operation = potential.get(); - ++i; + ++depth; - modification = modification.modifyChild(pathArg, operation.getChildPolicy()); + modification = modification.modifyChild(pathArg, operation, version); } return OperationWithModification.from(operation, modification); } private void checkSealed() { - Preconditions.checkState(sealed == 0, "Data Tree is sealed. No further modifications allowed."); + checkState(sealed == 0, "Data Tree is sealed. No further modifications allowed."); } @Override @@ -175,8 +186,8 @@ final class InMemoryDataTreeModification implements DataTreeModification { } @Override - public DataTreeModification newModification() { - Preconditions.checkState(sealed == 1, "Attempted to chain on an unsealed modification"); + public InMemoryDataTreeModification newModification() { + checkState(sealed == 1, "Attempted to chain on an unsealed modification"); if (rootNode.getOperation() == LogicalOperation.NONE) { // Simple fast case: just use the underlying modification @@ -188,10 +199,11 @@ final class InMemoryDataTreeModification implements DataTreeModification { * have same version each time this method is called. */ final TreeNode originalSnapshotRoot = snapshot.getRootNode(); - final Optional tempRoot = strategyTree.apply(rootNode, Optional.of(originalSnapshotRoot), version); - Preconditions.checkState(tempRoot.isPresent(), "Data tree root is not present, possibly removed by previous modification"); + final Optional tempRoot = getStrategy().apply(rootNode, Optional.of(originalSnapshotRoot), version); + checkState(tempRoot.isPresent(), "Data tree root is not present, possibly removed by previous modification"); - final InMemoryDataTreeSnapshot tempTree = new InMemoryDataTreeSnapshot(snapshot.getSchemaContext(), tempRoot.get(), strategyTree); + final InMemoryDataTreeSnapshot tempTree = new InMemoryDataTreeSnapshot(snapshot.getSchemaContext(), + tempRoot.get(), strategyTree); return tempTree.newModification(); } @@ -199,6 +211,10 @@ final class InMemoryDataTreeModification implements DataTreeModification { return version; } + boolean isSealed() { + return sealed == 1; + } + private static void applyChildren(final DataTreeModificationCursor cursor, final ModifiedNode node) { final Collection children = node.getChildren(); if (!children.isEmpty()) { @@ -212,59 +228,71 @@ final class InMemoryDataTreeModification implements DataTreeModification { private static void applyNode(final DataTreeModificationCursor cursor, final ModifiedNode node) { switch (node.getOperation()) { - case NONE: - break; - case DELETE: - cursor.delete(node.getIdentifier()); - break; - case MERGE: - cursor.merge(node.getIdentifier(), node.getWrittenValue()); - applyChildren(cursor, node); - break; - case TOUCH: - // TODO: we could improve efficiency of cursor use if we could understand - // nested TOUCH operations. One way of achieving that would be a proxy - // cursor, which would keep track of consecutive enter and exit calls - // and coalesce them. - applyChildren(cursor, node); - break; - case WRITE: - cursor.write(node.getIdentifier(), node.getWrittenValue()); - applyChildren(cursor, node); - break; - default: - throw new IllegalArgumentException("Unhandled node operation " + node.getOperation()); + case NONE: + break; + case DELETE: + cursor.delete(node.getIdentifier()); + break; + case MERGE: + cursor.merge(node.getIdentifier(), node.getWrittenValue()); + applyChildren(cursor, node); + break; + case TOUCH: + // TODO: we could improve efficiency of cursor use if we could understand + // nested TOUCH operations. One way of achieving that would be a proxy + // cursor, which would keep track of consecutive enter and exit calls + // and coalesce them. + applyChildren(cursor, node); + break; + case WRITE: + cursor.write(node.getIdentifier(), node.getWrittenValue()); + applyChildren(cursor, node); + break; + default: + throw new IllegalArgumentException("Unhandled node operation " + node.getOperation()); } } @Override - public void applyToCursor(final DataTreeModificationCursor cursor) { + public void applyToCursor(@Nonnull final DataTreeModificationCursor cursor) { for (final ModifiedNode child : rootNode.getChildren()) { applyNode(cursor, child); } } - private static void checkIdentifierReferencesData(final YangInstanceIdentifier path, final NormalizedNode data) { + static void checkIdentifierReferencesData(final PathArgument arg, final NormalizedNode data) { + checkArgument(arg.equals(data.getIdentifier()), + "Instance identifier references %s but data identifier is %s", arg, data.getIdentifier()); + } + + private void checkIdentifierReferencesData(final YangInstanceIdentifier path, + final NormalizedNode data) { + final PathArgument arg; + if (!path.isEmpty()) { - final PathArgument lastArg = path.getLastPathArgument(); - Preconditions.checkArgument(lastArg != null, "Instance identifier %s has invalid null path argument", path); - Preconditions.checkArgument(lastArg.equals(data.getIdentifier()), - "Instance identifier references %s but data identifier is %s", lastArg, data.getIdentifier()); + arg = path.getLastPathArgument(); + checkArgument(arg != null, "Instance identifier %s has invalid null path argument", path); } else { - final QName type = data.getNodeType(); - Preconditions.checkArgument(SchemaContext.NAME.equals(type), "Incorrect name %s of root node", type); + arg = rootNode.getIdentifier(); } + + checkIdentifierReferencesData(arg, data); + } + + @Override + public DataTreeModificationCursor createCursor(@Nonnull final YangInstanceIdentifier path) { + final OperationWithModification op = resolveModificationFor(path); + return openCursor(new InMemoryDataTreeModificationCursor(this, path, op)); } @Override public void ready() { - final boolean wasRunning = UPDATER.compareAndSet(this, 0, 1); - Preconditions.checkState(wasRunning, "Attempted to seal an already-sealed Data Tree."); + final boolean wasRunning = SEALED_UPDATER.compareAndSet(this, 0, 1); + checkState(wasRunning, "Attempted to seal an already-sealed Data Tree."); - AbstractReadyIterator current = AbstractReadyIterator.create(rootNode, strategyTree); + AbstractReadyIterator current = AbstractReadyIterator.create(rootNode, getStrategy()); do { - current = current.process(); + current = current.process(version); } while (current != null); } - }