From bb86472bd5abf18630abe60eaf3f20becd013fed Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Tue, 14 May 2019 10:15:19 +0200 Subject: [PATCH] Rework AbstractNormalizedNodePruner This refactors NormalizedNodePruner to use ReusableImmutableNormalizedNodeStreamWriter for creation of the actual NormalizedNode tree. It simplifies the implementation and allows the reuse of minor optimizations like LeafInterner. JIRA: CONTROLLER-1889 Change-Id: I93bd00bcff13245d808f7adf6122a6c20156e9fd Signed-off-by: Robert Varga --- .../AbstractNormalizedNodePruner.java | 182 +++++++++++------- .../NormalizedNodeBuilderWrapper.java | 68 ------- 2 files changed, 111 insertions(+), 139 deletions(-) delete mode 100644 opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/NormalizedNodeBuilderWrapper.java diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/AbstractNormalizedNodePruner.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/AbstractNormalizedNodePruner.java index 03467f39cb..a6d8801d77 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/AbstractNormalizedNodePruner.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/AbstractNormalizedNodePruner.java @@ -24,10 +24,10 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithV 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.stream.NormalizedNodeStreamWriter; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.ReusableImmutableNormalizedNodeStreamWriter; import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode; import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,13 +43,28 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite CLOSED; } + @FunctionalInterface + private interface WriterMethod { + + void apply(ReusableImmutableNormalizedNodeStreamWriter writer, T name) throws IOException; + } + + @FunctionalInterface + private interface SizedWriterMethod { + + void apply(ReusableImmutableNormalizedNodeStreamWriter writer, T name, int childSizeHint) throws IOException; + } + private static final Logger LOG = LoggerFactory.getLogger(AbstractNormalizedNodePruner.class); - private final Deque stack = new ArrayDeque<>(); + private final Deque> stack = new ArrayDeque<>(); + private final ReusableImmutableNormalizedNodeStreamWriter delegate = + ReusableImmutableNormalizedNodeStreamWriter.create(); private final DataSchemaContextTree tree; private DataSchemaContextNode nodePathSchemaNode; private State state = State.UNITIALIZED; + private int unknown; // FIXME: package-private to support unguarded NormalizedNodePruner access NormalizedNode normalizedNode; @@ -68,131 +83,136 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite final void initialize(final YangInstanceIdentifier nodePath) { nodePathSchemaNode = tree.findChild(nodePath).orElse(null); + unknown = 0; normalizedNode = null; stack.clear(); + delegate.reset(); state = State.OPEN; } @Override - public void startLeafNode(final NodeIdentifier name) { - addBuilder(Builders.leafBuilder().withNodeIdentifier(name), name); + public void startLeafNode(final NodeIdentifier name) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startLeafNode, name); } @Override - public void startLeafSet(final NodeIdentifier nodeIdentifier, final int count) { - addBuilder(Builders.leafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier); + public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startLeafSet, name, childSizeHint); } @Override - public void startOrderedLeafSet(final NodeIdentifier nodeIdentifier, final int str) { - addBuilder(Builders.orderedLeafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier); + public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startOrderedLeafSet, name, childSizeHint); } @Override public void startLeafSetEntryNode(final NodeWithValue name) throws IOException { - addBuilder(Builders.leafSetEntryBuilder().withNodeIdentifier(name), name); + enter(ReusableImmutableNormalizedNodeStreamWriter::startLeafSetEntryNode, name); } @Override - public void startContainerNode(final NodeIdentifier nodeIdentifier, final int count) { - addBuilder(Builders.containerBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier); + public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startContainerNode, name, childSizeHint); } @Override public void startYangModeledAnyXmlNode(final NodeIdentifier nodeIdentifier, final int count) { + // FIXME: implement this throw new UnsupportedOperationException("Not implemented yet"); } @Override - public void startUnkeyedList(final NodeIdentifier nodeIdentifier, final int count) { - addBuilder(Builders.unkeyedListBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier); + public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startUnkeyedList, name, childSizeHint); } @Override - public void startUnkeyedListItem(final NodeIdentifier nodeIdentifier, final int count) { - addBuilder(Builders.unkeyedListEntryBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier); + public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startUnkeyedListItem, name, childSizeHint); } @Override - public void startMapNode(final NodeIdentifier nodeIdentifier, final int count) { - addBuilder(Builders.mapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier); + public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startMapNode, name, childSizeHint); } @Override - public void startMapEntryNode(final NodeIdentifierWithPredicates nodeIdentifierWithPredicates, final int count) { - addBuilder(Builders.mapEntryBuilder().withNodeIdentifier(nodeIdentifierWithPredicates), - nodeIdentifierWithPredicates); + public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint) + throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startMapEntryNode, identifier, childSizeHint); } @Override - public void startOrderedMapNode(final NodeIdentifier nodeIdentifier, final int count) { - addBuilder(Builders.orderedMapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier); + public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startOrderedMapNode, name, childSizeHint); } @Override - public void startChoiceNode(final NodeIdentifier nodeIdentifier, final int count) { - addBuilder(Builders.choiceBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier); + public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startChoiceNode, name, childSizeHint); } @Override - public void startAugmentationNode(final AugmentationIdentifier augmentationIdentifier) { - addBuilder(Builders.augmentationBuilder().withNodeIdentifier(augmentationIdentifier), augmentationIdentifier); + public void startAugmentationNode(final AugmentationIdentifier identifier) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startAugmentationNode, identifier); } @Override - public void startAnyxmlNode(final NodeIdentifier name) { - addBuilder(Builders.anyXmlBuilder().withNodeIdentifier(name), name); + public void startAnyxmlNode(final NodeIdentifier name) throws IOException { + enter(ReusableImmutableNormalizedNodeStreamWriter::startAnyxmlNode, name); } @Override - public void domSourceValue(final DOMSource value) { - setValue(value); + public void domSourceValue(final DOMSource value) throws IOException { + checkNotSealed(); + if (unknown == 0) { + delegate.domSourceValue(value); + } } @Override - public void scalarValue(final Object value) { - setValue(value); + public void scalarValue(final Object value) throws IOException { + checkNotSealed(); + if (unknown == 0) { + delegate.scalarValue(value); + } } @Override - public void endNode() { + public void endNode() throws IOException { checkNotSealed(); - final NormalizedNodeBuilderWrapper child; - try { - child = stack.pop(); - } catch (NoSuchElementException e) { - throw new IllegalStateException("endNode called on an empty stack", e); - } - - if (child.getSchema() == null) { - LOG.debug("Schema not found for {}", child.identifier()); - if (stack.isEmpty()) { - normalizedNode = null; - state = State.CLOSED; + if (unknown == 0) { + try { + stack.pop(); + } catch (NoSuchElementException e) { + throw new IllegalStateException("endNode called on an empty stack", e); + } + delegate.endNode(); + } else { + unknown--; + if (unknown != 0) { + // Still at unknown, do not attempt to create result + return; } - return; } - final NormalizedNode newNode = child.build(); - final NormalizedNodeBuilderWrapper parent = stack.peek(); - if (parent == null) { - normalizedNode = newNode; + if (stack.isEmpty()) { + normalizedNode = delegate.getResult(); state = State.CLOSED; - } else { - parent.addChild(newNode); } } @Override - public void close() { + public void close() throws IOException { state = State.CLOSED; stack.clear(); + delegate.close(); } @Override - public void flush() { - // No-op + public void flush() throws IOException { + delegate.flush(); } /** @@ -210,27 +230,47 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite checkState(state == State.OPEN, "Illegal operation in state %s", state); } - private void setValue(final Object value) { + private boolean enter(final PathArgument name) { checkNotSealed(); - final NormalizedNodeBuilderWrapper current = stack.peek(); - checkState(current != null, "Attempted to set value %s while no node is open", value); - current.setValue(value); - } - private > NormalizedNodeBuilderWrapper addBuilder(final T builder, - final PathArgument identifier) { - checkNotSealed(); + if (unknown != 0) { + LOG.debug("Skipping child {} in unknown subtree", name); + unknown++; + return false; + } - final DataSchemaContextNode schemaNode; - final NormalizedNodeBuilderWrapper parent = stack.peek(); + final DataSchemaContextNode schema; + final DataSchemaContextNode parent = stack.peek(); if (parent != null) { - schemaNode = parent.childSchema(identifier); + schema = parent.getChild(name); } else { - schemaNode = nodePathSchemaNode; + schema = nodePathSchemaNode; } - NormalizedNodeBuilderWrapper wrapper = new NormalizedNodeBuilderWrapper(builder, identifier, schemaNode); - stack.push(wrapper); - return wrapper; + if (schema == null) { + LOG.debug("Schema not found for {}", name); + unknown = 1; + return false; + } + + stack.push(schema); + final DataSchemaNode dataSchema = schema.getDataSchemaNode(); + if (dataSchema != null) { + delegate.nextDataSchemaNode(dataSchema); + } + return true; + } + + private void enter(final WriterMethod method, final A name) throws IOException { + if (enter(name)) { + method.apply(delegate, name); + } + } + + private void enter(final SizedWriterMethod method, final A name, final int size) + throws IOException { + if (enter(name)) { + method.apply(delegate, name, size); + } } } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/NormalizedNodeBuilderWrapper.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/NormalizedNodeBuilderWrapper.java deleted file mode 100644 index 385376c527..0000000000 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/NormalizedNodeBuilderWrapper.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2015 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.cluster.datastore.node.utils.transformer; - -import static com.google.common.base.Preconditions.checkState; -import static java.util.Objects.requireNonNull; - -import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder; -import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode; - -final class NormalizedNodeBuilderWrapper { - @SuppressWarnings("rawtypes") - private final NormalizedNodeBuilder builder; - private final PathArgument identifier; - private final DataSchemaContextNode schemaNode; - - NormalizedNodeBuilderWrapper(final NormalizedNodeBuilder builder, - final PathArgument identifier, final @Nullable DataSchemaContextNode schemaNode) { - this.builder = requireNonNull(builder); - this.identifier = requireNonNull(identifier); - this.schemaNode = schemaNode; - } - - PathArgument identifier() { - return identifier; - } - - @Nullable DataSchemaContextNode getSchema() { - return schemaNode; - } - - @Nullable DataSchemaContextNode childSchema(final PathArgument child) { - if (schemaNode == null) { - return null; - } - - checkState(builder instanceof NormalizedNodeContainerBuilder, - "Attempted to lookup child %s in non-container %s", schemaNode); - return schemaNode.getChild(child); - } - - NormalizedNode build() { - return builder.build(); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - void addChild(final NormalizedNode child) { - checkState(builder instanceof NormalizedNodeContainerBuilder, - "Attempted to add child %s to non-container builder %s", child, builder); - ((NormalizedNodeContainerBuilder) builder).addChild(child); - } - - @SuppressWarnings("unchecked") - void setValue(final Object value) { - checkState(!(builder instanceof NormalizedNodeContainerBuilder), - "Attempted to set value %s on container builder %s", value, builder); - builder.withValue(value); - } -} -- 2.36.6