+
+ Version getVersion() {
+ return version;
+ }
+
+ boolean isSealed() {
+ return sealed == 1;
+ }
+
+ private static void applyChildren(final DataTreeModificationCursor cursor, final ModifiedNode node) {
+ final Collection<ModifiedNode> children = node.getChildren();
+ if (!children.isEmpty()) {
+ cursor.enter(node.getIdentifier());
+ for (final ModifiedNode child : children) {
+ applyNode(cursor, child);
+ }
+ cursor.exit();
+ }
+ }
+
+ 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());
+ }
+ }
+
+ @Override
+ public void applyToCursor(final DataTreeModificationCursor cursor) {
+ for (final ModifiedNode child : rootNode.getChildren()) {
+ applyNode(cursor, child);
+ }
+ }
+
+ static void checkIdentifierReferencesData(final PathArgument arg, final NormalizedNode<?, ?> data) {
+ Preconditions.checkArgument(arg.equals(data.getIdentifier()),
+ "Instance identifier references %s but data identifier is %s", arg, data.getIdentifier());
+ }
+
+ private static void checkIdentifierReferencesData(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ if (!path.isEmpty()) {
+ final PathArgument lastArg = path.getLastPathArgument();
+ Preconditions.checkArgument(lastArg != null, "Instance identifier %s has invalid null path argument", path);
+ checkIdentifierReferencesData(lastArg, data);
+ } else {
+ final QName type = data.getNodeType();
+ Preconditions.checkArgument(SchemaContext.NAME.equals(type), "Incorrect name %s of root node", type);
+ }
+ }
+
+ @Override
+ public DataTreeModificationCursor createCursor(final YangInstanceIdentifier path) {
+ final OperationWithModification op = resolveModificationFor(path);
+ return openCursor(new InMemoryDataTreeModificationCursor(this, path, op));
+ }
+
+ @Override
+ public void ready() {
+ final boolean wasRunning = SEALED_UPDATER.compareAndSet(this, 0, 1);
+ Preconditions.checkState(wasRunning, "Attempted to seal an already-sealed Data Tree.");
+
+ AbstractReadyIterator current = AbstractReadyIterator.create(rootNode, strategyTree);
+ do {
+ current = current.process(version);
+ } while (current != null);
+ }