--- /dev/null
+/*
+ * 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 java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+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.NormalizedNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The NormalizedNodePruner removes all nodes from the input NormalizedNode that do not have a corresponding
+ * schema element in the passed in SchemaContext.
+ */
+abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWriter {
+ enum State {
+ UNITIALIZED,
+ OPEN,
+ CLOSED;
+ }
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractNormalizedNodePruner.class);
+
+ private final Deque<NormalizedNodeBuilderWrapper> stack = new ArrayDeque<>();
+ private final DataSchemaContextTree tree;
+
+ private DataSchemaContextNode<?> nodePathSchemaNode;
+ private State state = State.UNITIALIZED;
+
+ // FIXME: package-private to support unguarded NormalizedNodePruner access
+ NormalizedNode<?, ?> normalizedNode;
+
+ AbstractNormalizedNodePruner(final DataSchemaContextTree tree) {
+ this.tree = requireNonNull(tree);
+ }
+
+ AbstractNormalizedNodePruner(final SchemaContext schemaContext) {
+ this(DataSchemaContextTree.from(schemaContext));
+ }
+
+ final DataSchemaContextTree getTree() {
+ return tree;
+ }
+
+ final void initialize(final YangInstanceIdentifier nodePath) {
+ nodePathSchemaNode = tree.findChild(nodePath).orElse(null);
+ normalizedNode = null;
+ stack.clear();
+ state = State.OPEN;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void leafNode(final NodeIdentifier nodeIdentifier, final Object value) {
+ checkNotSealed();
+
+ NormalizedNodeBuilderWrapper parent = stack.peek();
+ LeafNode<Object> leafNode = Builders.leafBuilder().withNodeIdentifier(nodeIdentifier).withValue(value).build();
+ if (parent != null) {
+ if (hasValidSchema(nodeIdentifier.getNodeType(), parent)) {
+ parent.builder().addChild(leafNode);
+ }
+ } else {
+ // If there's no parent node then this is a stand alone LeafNode.
+ if (nodePathSchemaNode != null) {
+ this.normalizedNode = leafNode;
+ }
+
+ state = State.CLOSED;
+ }
+ }
+
+ @Override
+ public void startLeafSet(final NodeIdentifier nodeIdentifier, final int count) {
+ addBuilder(Builders.leafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+ }
+
+ @Override
+ public void startOrderedLeafSet(final NodeIdentifier nodeIdentifier, final int str) {
+ addBuilder(Builders.orderedLeafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void leafSetEntryNode(final QName name, final Object value) {
+ checkNotSealed();
+
+ NormalizedNodeBuilderWrapper parent = stack.peek();
+ if (parent != null) {
+ if (hasValidSchema(name, parent)) {
+ parent.builder().addChild(Builders.leafSetEntryBuilder().withValue(value)
+ .withNodeIdentifier(new NodeWithValue<>(parent.nodeType(), value))
+ .build());
+ }
+ } else {
+ // If there's no parent LeafSetNode then this is a stand alone
+ // LeafSetEntryNode.
+ if (nodePathSchemaNode != null) {
+ this.normalizedNode = Builders.leafSetEntryBuilder().withValue(value).withNodeIdentifier(
+ new NodeWithValue<>(name, value)).build();
+ }
+
+ state = State.CLOSED;
+ }
+ }
+
+ @Override
+ public void startContainerNode(final NodeIdentifier nodeIdentifier, final int count) {
+ addBuilder(Builders.containerBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+ }
+
+ @Override
+ public void startYangModeledAnyXmlNode(final NodeIdentifier nodeIdentifier, final int count) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ @Override
+ public void startUnkeyedList(final NodeIdentifier nodeIdentifier, final int count) {
+ addBuilder(Builders.unkeyedListBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+ }
+
+ @Override
+ public void startUnkeyedListItem(final NodeIdentifier nodeIdentifier, final int count) {
+ addBuilder(Builders.unkeyedListEntryBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+ }
+
+ @Override
+ public void startMapNode(final NodeIdentifier nodeIdentifier, final int count) {
+ addBuilder(Builders.mapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+ }
+
+ @Override
+ public void startMapEntryNode(final NodeIdentifierWithPredicates nodeIdentifierWithPredicates, final int count) {
+ addBuilder(Builders.mapEntryBuilder().withNodeIdentifier(nodeIdentifierWithPredicates),
+ nodeIdentifierWithPredicates);
+ }
+
+ @Override
+ public void startOrderedMapNode(final NodeIdentifier nodeIdentifier, final int count) {
+ addBuilder(Builders.orderedMapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+ }
+
+ @Override
+ public void startChoiceNode(final NodeIdentifier nodeIdentifier, final int count) {
+ addBuilder(Builders.choiceBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+ }
+
+ @Override
+ public void startAugmentationNode(final AugmentationIdentifier augmentationIdentifier) {
+ addBuilder(Builders.augmentationBuilder().withNodeIdentifier(augmentationIdentifier), augmentationIdentifier);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void anyxmlNode(final NodeIdentifier nodeIdentifier, final Object value) {
+ checkNotSealed();
+
+ NormalizedNodeBuilderWrapper parent = stack.peek();
+ AnyXmlNode anyXmlNode = Builders.anyXmlBuilder().withNodeIdentifier(nodeIdentifier).withValue((DOMSource) value)
+ .build();
+ if (parent != null) {
+ if (hasValidSchema(nodeIdentifier.getNodeType(), parent)) {
+ parent.builder().addChild(anyXmlNode);
+ }
+ } else {
+ // If there's no parent node then this is a stand alone AnyXmlNode.
+ if (nodePathSchemaNode != null) {
+ this.normalizedNode = anyXmlNode;
+ }
+
+ state = State.CLOSED;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void endNode() {
+ 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;
+ }
+ return;
+ }
+
+ final NormalizedNode<?, ?> newNode = child.builder().build();
+ final NormalizedNodeBuilderWrapper parent = stack.peek();
+ if (parent == null) {
+ normalizedNode = newNode;
+ state = State.CLOSED;
+ } else {
+ parent.builder().addChild(newNode);
+ }
+ }
+
+ @Override
+ public void close() {
+ state = State.CLOSED;
+ stack.clear();
+ }
+
+ @Override
+ public void flush() {
+ // No-op
+ }
+
+ /**
+ * Return the resulting normalized node.
+ *
+ * @return Resulting node for the path, if it was not pruned
+ * @throws IllegalStateException if this pruner has not been closed
+ */
+ public final Optional<NormalizedNode<?, ?>> getResult() {
+ checkState(state == State.CLOSED, "Cannot get result in state %s", state);
+ return Optional.ofNullable(normalizedNode);
+ }
+
+ private void checkNotSealed() {
+ checkState(state == State.OPEN, "Illegal operation in state %s", state);
+ }
+
+ private static boolean hasValidSchema(final QName name, final NormalizedNodeBuilderWrapper parent) {
+ final DataSchemaContextNode<?> parentSchema = parent.getSchema();
+ final boolean valid = parentSchema != null && parentSchema.getChild(name) != null;
+ if (!valid) {
+ LOG.debug("Schema not found for {}", name);
+ }
+
+ return valid;
+ }
+
+ private NormalizedNodeBuilderWrapper addBuilder(final NormalizedNodeContainerBuilder<?, ?, ?, ?> builder,
+ final PathArgument identifier) {
+ checkNotSealed();
+
+ final DataSchemaContextNode<?> schemaNode;
+ final NormalizedNodeBuilderWrapper parent = stack.peek();
+ if (parent != null) {
+ final DataSchemaContextNode<?> parentSchema = parent.getSchema();
+ schemaNode = parentSchema == null ? null : parentSchema.getChild(identifier);
+ } else {
+ schemaNode = nodePathSchemaNode;
+ }
+
+ NormalizedNodeBuilderWrapper wrapper = new NormalizedNodeBuilderWrapper(builder, identifier, schemaNode);
+ stack.push(wrapper);
+ return wrapper;
+ }
+}
*/
package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
-import static com.google.common.base.Preconditions.checkState;
-
import java.net.URI;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.NoSuchElementException;
-import javax.xml.transform.dom.DOMSource;
-import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
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.NormalizedNodeContainerBuilder;
-import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
-import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* The NormalizedNodePruner removes all nodes from the input NormalizedNode that do not have a corresponding
* schema element in the passed in SchemaContext.
+ *
+ * @deprecated Use {@link AbstractNormalizedNodePruner} instead.
*/
-public class NormalizedNodePruner implements NormalizedNodeStreamWriter {
- private static final Logger LOG = LoggerFactory.getLogger(NormalizedNodePruner.class);
-
+@Deprecated
+public class NormalizedNodePruner extends AbstractNormalizedNodePruner {
public static final URI BASE_NAMESPACE = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0");
- private final Deque<NormalizedNodeBuilderWrapper> stack = new ArrayDeque<>();
- private final DataSchemaContextNode<?> nodePathSchemaNode;
-
- private NormalizedNode<?, ?> normalizedNode;
- private boolean sealed = false;
-
public NormalizedNodePruner(final YangInstanceIdentifier nodePath, final SchemaContext schemaContext) {
- nodePathSchemaNode = DataSchemaContextTree.from(schemaContext).findChild(nodePath).orElse(null);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public void leafNode(final NodeIdentifier nodeIdentifier, final Object value) {
- checkNotSealed();
-
- NormalizedNodeBuilderWrapper parent = stack.peek();
- LeafNode<Object> leafNode = Builders.leafBuilder().withNodeIdentifier(nodeIdentifier).withValue(value).build();
- if (parent != null) {
- if (hasValidSchema(nodeIdentifier.getNodeType(), parent)) {
- parent.builder().addChild(leafNode);
- }
- } else {
- // If there's no parent node then this is a stand alone LeafNode.
- if (nodePathSchemaNode != null) {
- this.normalizedNode = leafNode;
- }
-
- sealed = true;
- }
- }
-
- @Override
- public void startLeafSet(final NodeIdentifier nodeIdentifier, final int count) {
- addBuilder(Builders.leafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
- }
-
- @Override
- public void startOrderedLeafSet(final NodeIdentifier nodeIdentifier, final int str) {
- addBuilder(Builders.orderedLeafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public void leafSetEntryNode(final QName name, final Object value) {
- checkNotSealed();
-
- NormalizedNodeBuilderWrapper parent = stack.peek();
- if (parent != null) {
- if (hasValidSchema(name, parent)) {
- parent.builder().addChild(Builders.leafSetEntryBuilder().withValue(value)
- .withNodeIdentifier(new NodeWithValue<>(parent.nodeType(), value))
- .build());
- }
- } else {
- // If there's no parent LeafSetNode then this is a stand alone
- // LeafSetEntryNode.
- if (nodePathSchemaNode != null) {
- this.normalizedNode = Builders.leafSetEntryBuilder().withValue(value).withNodeIdentifier(
- new NodeWithValue<>(name, value)).build();
- }
-
- sealed = true;
- }
- }
-
- @Override
- public void startContainerNode(final NodeIdentifier nodeIdentifier, final int count) {
- addBuilder(Builders.containerBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
- }
-
- @Override
- public void startYangModeledAnyXmlNode(final NodeIdentifier nodeIdentifier, final int count) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- @Override
- public void startUnkeyedList(final NodeIdentifier nodeIdentifier, final int count) {
- addBuilder(Builders.unkeyedListBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
- }
-
- @Override
- public void startUnkeyedListItem(final NodeIdentifier nodeIdentifier, final int count) {
- addBuilder(Builders.unkeyedListEntryBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
- }
-
- @Override
- public void startMapNode(final NodeIdentifier nodeIdentifier, final int count) {
- addBuilder(Builders.mapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
- }
-
- @Override
- public void startMapEntryNode(final NodeIdentifierWithPredicates nodeIdentifierWithPredicates, final int count) {
- addBuilder(Builders.mapEntryBuilder().withNodeIdentifier(nodeIdentifierWithPredicates),
- nodeIdentifierWithPredicates);
- }
-
- @Override
- public void startOrderedMapNode(final NodeIdentifier nodeIdentifier, final int count) {
- addBuilder(Builders.orderedMapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
- }
-
- @Override
- public void startChoiceNode(final NodeIdentifier nodeIdentifier, final int count) {
- addBuilder(Builders.choiceBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
- }
-
- @Override
- public void startAugmentationNode(final AugmentationIdentifier augmentationIdentifier) {
- addBuilder(Builders.augmentationBuilder().withNodeIdentifier(augmentationIdentifier), augmentationIdentifier);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public void anyxmlNode(final NodeIdentifier nodeIdentifier, final Object value) {
- checkNotSealed();
-
- NormalizedNodeBuilderWrapper parent = stack.peek();
- AnyXmlNode anyXmlNode = Builders.anyXmlBuilder().withNodeIdentifier(nodeIdentifier).withValue((DOMSource) value)
- .build();
- if (parent != null) {
- if (hasValidSchema(nodeIdentifier.getNodeType(), parent)) {
- parent.builder().addChild(anyXmlNode);
- }
- } else {
- // If there's no parent node then this is a stand alone AnyXmlNode.
- if (nodePathSchemaNode != null) {
- this.normalizedNode = anyXmlNode;
- }
-
- sealed = true;
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public void endNode() {
- 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());
- return;
- }
-
- NormalizedNode<?, ?> newNode = child.builder().build();
- if (stack.size() > 0) {
- NormalizedNodeBuilderWrapper parent = stack.peek();
- parent.builder().addChild(newNode);
- } else {
- this.normalizedNode = newNode;
- sealed = true;
- }
- }
-
- @Override
- public void close() {
- sealed = true;
- }
-
- @Override
- public void flush() {
- // No-op
+ super(schemaContext);
+ initialize(nodePath);
}
public NormalizedNode<?, ?> normalizedNode() {
return normalizedNode;
}
-
- private void checkNotSealed() {
- checkState(!sealed, "Pruner can be used only once");
- }
-
- private static boolean hasValidSchema(final QName name, final NormalizedNodeBuilderWrapper parent) {
- final DataSchemaContextNode<?> parentSchema = parent.getSchema();
- final boolean valid = parentSchema != null && parentSchema.getChild(name) != null;
- if (!valid) {
- LOG.debug("Schema not found for {}", name);
- }
-
- return valid;
- }
-
- private NormalizedNodeBuilderWrapper addBuilder(final NormalizedNodeContainerBuilder<?, ?, ?, ?> builder,
- final PathArgument identifier) {
- checkNotSealed();
-
- final DataSchemaContextNode<?> schemaNode;
- final NormalizedNodeBuilderWrapper parent = stack.peek();
- if (parent != null) {
- final DataSchemaContextNode<?> parentSchema = parent.getSchema();
- schemaNode = parentSchema == null ? null : parentSchema.getChild(identifier);
- } else {
- schemaNode = nodePathSchemaNode;
- }
-
- NormalizedNodeBuilderWrapper wrapper = new NormalizedNodeBuilderWrapper(builder, identifier, schemaNode);
- stack.push(wrapper);
- return wrapper;
- }
}
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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 com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * The NormalizedNodePruner removes all nodes from the input NormalizedNode that do not have a corresponding
+ * schema element in the passed in SchemaContext.
+ *
+ * <p>
+ * Unlike {@link NormalizedNodePruner}, this class can be reused multiple times and must be initialized before each use
+ * through {@link #initializeForPath(YangInstanceIdentifier)}.
+ */
+@Beta
+public final class ReusableNormalizedNodePruner extends AbstractNormalizedNodePruner {
+ private ReusableNormalizedNodePruner(final SchemaContext schemaContext) {
+ super(schemaContext);
+ }
+
+ private ReusableNormalizedNodePruner(final DataSchemaContextTree tree) {
+ super(tree);
+ }
+
+ /**
+ * Create a new pruner bound to a SchemaContext.
+ *
+ * @param schemaContext SchemaContext to use
+ * @return A new uninitialized pruner
+ * @throws NullPointerException if {@code schemaContext} is null
+ */
+ public static @NonNull ReusableNormalizedNodePruner forSchemaContext(final SchemaContext schemaContext) {
+ return new ReusableNormalizedNodePruner(schemaContext);
+ }
+
+ /**
+ * Create a new pruner bound to a DataSchemaContextTree. This is a more efficient alternative of
+ * {@link #forSchemaContext(SchemaContext)}.
+ *
+ * @param tree DataSchemaContextTree to use
+ * @return A new uninitialized pruner
+ * @throws NullPointerException if {@code schemaContext} is null
+ */
+ public static @NonNull ReusableNormalizedNodePruner forDataSchemaContext(final DataSchemaContextTree tree) {
+ return new ReusableNormalizedNodePruner(tree);
+ }
+
+ /**
+ * Return a new instance, which is backed but the same DataSchemaContextTree, but does not share any state and is
+ * uninitialized. This is equivalent to {@link #forDataSchemaContext(DataSchemaContextTree)} and is provided for
+ * convenience.
+ *
+ * @return A new uninitialized pruner bound to the same SchemaContext as this one.
+ */
+ public @NonNull ReusableNormalizedNodePruner duplicate() {
+ return new ReusableNormalizedNodePruner(getTree());
+ }
+
+ /**
+ * Initialize this pruner for processing a node at specified path.
+ *
+ * @param path Path that will be processed next
+ * @throws NullPointerException if {@code path} is null
+ */
+ public void initializeForPath(final YangInstanceIdentifier path) {
+ initialize(path);
+ }
+}