Remove NormalizedNodePruner
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / main / java / org / opendaylight / controller / cluster / datastore / node / utils / transformer / AbstractNormalizedNodePruner.java
index 9ce039cd1a4e93260dc646007d6dec6d697eb9f0..f0ef49645a66954b4e15f5d393c1abe40be9ec7a 100644 (file)
@@ -8,28 +8,27 @@
 package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
 
 import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
+import java.io.IOException;
 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.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;
@@ -45,16 +44,29 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite
         CLOSED;
     }
 
+    @FunctionalInterface
+    interface WriterMethod<T extends PathArgument> {
+
+        void apply(ReusableImmutableNormalizedNodeStreamWriter writer, T name) throws IOException;
+    }
+
+    @FunctionalInterface
+    interface SizedWriterMethod<T extends PathArgument> {
+
+        void apply(ReusableImmutableNormalizedNodeStreamWriter writer, T name, int childSizeHint) throws IOException;
+    }
+
     private static final Logger LOG = LoggerFactory.getLogger(AbstractNormalizedNodePruner.class);
 
-    private final Deque<NormalizedNodeBuilderWrapper> stack = new ArrayDeque<>();
+    private final Deque<DataSchemaContextNode<?>> stack = new ArrayDeque<>();
+    private final ReusableImmutableNormalizedNodeStreamWriter delegate =
+            ReusableImmutableNormalizedNodeStreamWriter.create();
     private final DataSchemaContextTree tree;
 
     private DataSchemaContextNode<?> nodePathSchemaNode;
+    private NormalizedNode<?, ?> normalizedNode;
     private State state = State.UNITIALIZED;
-
-    // FIXME: package-private to support unguarded NormalizedNodePruner access
-    NormalizedNode<?, ?> normalizedNode;
+    private int unknown;
 
     AbstractNormalizedNodePruner(final DataSchemaContextTree tree) {
         this.tree = requireNonNull(tree);
@@ -70,174 +82,151 @@ 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;
     }
 
-    @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;
-        }
+    public final 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 final 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 final void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startOrderedLeafSet, name, childSizeHint);
     }
 
-    @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;
-        }
+    public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startLeafSetEntryNode, name);
     }
 
     @Override
-    public void startContainerNode(final NodeIdentifier nodeIdentifier, final int count) {
-        addBuilder(Builders.containerBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+    public final 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) {
+    public final 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 final 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 final 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 final 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 final 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 final 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 final void startAugmentationNode(final AugmentationIdentifier identifier) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startAugmentationNode, identifier);
     }
 
-    @SuppressWarnings("unchecked")
     @Override
-    public void anyxmlNode(final NodeIdentifier nodeIdentifier, final Object value) {
-        checkNotSealed();
+    public final  boolean startAnyxmlNode(final NodeIdentifier name, final Class<?> objectModel) throws IOException {
+        if (enter(name)) {
+            verify(delegate.startAnyxmlNode(name, objectModel),
+                "Unexpected failure to stream DOMSource node %s model %s", name, objectModel);
+        }
+        return true;
+    }
 
-        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;
-            }
+    @Override
+    public final boolean startAnydataNode(final NodeIdentifier name, final Class<?> objectModel) throws IOException {
+        // FIXME: we do not support anydata nodes yet
+        return false;
+    }
 
-            state = State.CLOSED;
+    @Override
+    public final  void domSourceValue(final DOMSource value) throws IOException {
+        checkNotSealed();
+        if (unknown == 0) {
+            delegate.domSourceValue(value);
         }
     }
 
-    @SuppressWarnings("unchecked")
     @Override
-    public void endNode() {
+    public final void scalarValue(final Object value) throws IOException {
         checkNotSealed();
-
-        final NormalizedNodeBuilderWrapper child;
-        try {
-            child = stack.pop();
-        } catch (NoSuchElementException e) {
-            throw new IllegalStateException("endNode called on an empty stack", e);
+        if (unknown == 0) {
+            delegate.scalarValue(translateScalar(currentSchema(), value));
         }
+    }
 
-        if (child.getSchema() == null) {
-            LOG.debug("Schema not found for {}", child.identifier());
-            if (stack.isEmpty()) {
-                normalizedNode = null;
-                state = State.CLOSED;
+    Object translateScalar(final DataSchemaContextNode<?> context, final Object value) throws IOException {
+        // Default is pass-through
+        return value;
+    }
+
+    @Override
+    public final void endNode() throws IOException {
+        checkNotSealed();
+
+        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.builder().build();
-        final NormalizedNodeBuilderWrapper parent = stack.peek();
-        if (parent == null) {
-            normalizedNode = newNode;
+        if (stack.isEmpty()) {
+            normalizedNode = delegate.getResult();
             state = State.CLOSED;
-        } else {
-            parent.builder().addChild(newNode);
         }
     }
 
     @Override
-    public void close() {
+    public final void close() throws IOException {
         state = State.CLOSED;
         stack.clear();
+        delegate.close();
     }
 
     @Override
-    public void flush() {
-        // No-op
+    public final void flush() throws IOException {
+        delegate.flush();
     }
 
     /**
@@ -255,31 +244,51 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite
         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) {
+    private boolean enter(final PathArgument name) {
+        checkNotSealed();
+
+        if (unknown != 0) {
+            LOG.debug("Skipping child {} in unknown subtree", name);
+            unknown++;
+            return false;
+        }
+
+        final DataSchemaContextNode<?> schema;
+        final DataSchemaContextNode<?> parent = currentSchema();
+        if (parent != null) {
+            schema = parent.getChild(name);
+        } else {
+            schema = nodePathSchemaNode;
+        }
+
+        if (schema == null) {
             LOG.debug("Schema not found for {}", name);
+            unknown = 1;
+            return false;
         }
 
-        return valid;
+        stack.push(schema);
+        final DataSchemaNode dataSchema = schema.getDataSchemaNode();
+        if (dataSchema != null) {
+            delegate.nextDataSchemaNode(dataSchema);
+        }
+        return true;
     }
 
-    private NormalizedNodeBuilderWrapper addBuilder(final NormalizedNodeContainerBuilder<?, ?, ?, ?> builder,
-            final PathArgument identifier) {
-        checkNotSealed();
+    final <A extends PathArgument> void enter(final WriterMethod<A> method, final A name) throws IOException {
+        if (enter(name)) {
+            method.apply(delegate, name);
+        }
+    }
 
-        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;
+    final <A extends PathArgument> void enter(final SizedWriterMethod<A> method, final A name, final int size)
+            throws IOException {
+        if (enter(name)) {
+            method.apply(delegate, name, size);
         }
+    }
 
-        NormalizedNodeBuilderWrapper wrapper = new NormalizedNodeBuilderWrapper(builder, identifier, schemaNode);
-        stack.push(wrapper);
-        return wrapper;
+    final DataSchemaContextNode<?> currentSchema() {
+        return stack.peek();
     }
 }