All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.restconf.server.spi.NormalizedNodeWriter Maven / Gradle / Ivy

/*
 * Copyright (c) 2024 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.restconf.server.spi;

import static java.util.Objects.requireNonNull;

import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.restconf.api.query.DepthParam;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.schema.AnydataNode;
import org.opendaylight.yangtools.yang.data.api.schema.AnyxmlNode;
import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;

/**
 * This is an experimental iterator over a {@link NormalizedNode}. This is essentially
 * the opposite of a {@link javax.xml.stream.XMLStreamReader} -- unlike instantiating an iterator over
 * the backing data, this encapsulates a {@link NormalizedNodeStreamWriter} and allows
 * us to write multiple nodes.
 */
@NonNullByDefault
public abstract class NormalizedNodeWriter implements Flushable, Closeable {
    protected final NormalizedNodeStreamWriter writer;

    NormalizedNodeWriter(final NormalizedNodeStreamWriter writer) {
        this.writer = requireNonNull(writer);
    }

    /**
     * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
     *
     * @param writer Back-end writer
     * @param maxDepth Maximal depth to write
     * @return A new instance.
     */
    public static final NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
            final @Nullable DepthParam maxDepth) {
        return forStreamWriter(writer, true,  maxDepth, null);
    }

    /**
     * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
     *
     * @param writer Back-end writer
     * @param maxDepth Maximal depth to write
     * @param fields Selected child nodes to write
     * @return A new instance.
     */
    public static final NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
            final @Nullable DepthParam maxDepth, final @Nullable List> fields) {
        return forStreamWriter(writer, true,  maxDepth, fields);
    }

    /**
     * Create a new writer backed by a {@link NormalizedNodeStreamWriter}. Unlike the simple
     * {@link #forStreamWriter(NormalizedNodeStreamWriter, DepthParam, List)} method, this allows the caller to
     * switch off RFC6020 XML compliance, providing better throughput. The reason is that the XML mapping rules in
     * RFC6020 require the encoding to emit leaf nodes which participate in a list's key first and in the order in which
     * they are defined in the key. For JSON, this requirement is completely relaxed and leaves can be ordered in any
     * way we see fit. The former requires a bit of work: first a lookup for each key and then for each emitted node we
     * need to check whether it was already emitted.
     *
     * @param writer Back-end writer
     * @param orderKeyLeaves whether the returned instance should be RFC6020 XML compliant.
     * @param depth Maximal depth to write
     * @param fields Selected child nodes to write
     * @return A new instance.
     */
    public static final NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
            final boolean orderKeyLeaves, final @Nullable DepthParam depth, final @Nullable List> fields) {
        return new DefaultNormalizedNodeWriter(writer, !orderKeyLeaves, depth, fields);
    }

    @Override
    public final void flush() throws IOException {
        writer.flush();
    }

    @Override
    public final void close() throws IOException {
        writer.flush();
        writer.close();
    }

    /**
     * Iterate over the provided {@link NormalizedNode} and emit write events to the encapsulated
     * {@link NormalizedNodeStreamWriter}.
     *
     * @param node Node
     * @return {@code ParameterAwareNormalizedNodeWriter}
     * @throws IOException when thrown from the backing writer.
     */
    public final NormalizedNodeWriter write(final NormalizedNode node) throws IOException {
        if (node instanceof ContainerNode n) {
            writeContainer(n);
        } else if (node instanceof MapNode n) {
            writeMap(n);
        } else if (node instanceof MapEntryNode n) {
            writeMapEntry(n);
        } else if (node instanceof LeafNode n) {
            writeLeaf(n);
        } else if (node instanceof ChoiceNode n) {
            writeChoice(n);
        } else if (node instanceof UnkeyedListNode n) {
            writeUnkeyedList(n);
        } else if (node instanceof UnkeyedListEntryNode n) {
            writeUnkeyedListEntry(n);
        } else if (node instanceof LeafSetNode n) {
            writeLeafSet(n);
        } else if (node instanceof LeafSetEntryNode n) {
            writeLeafSetEntry(n);
        } else if (node instanceof AnydataNode n) {
            writeAnydata(n);
        } else if (node instanceof AnyxmlNode n) {
            writeAnyxml(n);
        } else {
            throw new IOException("Unhandled contract " + node.contract().getSimpleName());
        }
        return this;
    }

    protected abstract void writeAnydata(AnydataNode node) throws IOException;

    protected abstract void writeAnyxml(AnyxmlNode node) throws IOException;

    protected abstract void writeChoice(ChoiceNode node) throws IOException;

    protected abstract void writeContainer(ContainerNode node) throws IOException;

    protected abstract void writeLeaf(LeafNode node) throws IOException;

    protected abstract void writeLeafSet(LeafSetNode node) throws IOException;

    protected abstract void writeLeafSetEntry(LeafSetEntryNode node) throws IOException;

    protected abstract void writeMap(MapNode node) throws IOException;

    protected abstract void writeMapEntry(MapEntryNode node) throws IOException;

    protected abstract void writeUnkeyedList(UnkeyedListNode node) throws IOException;

    protected abstract void writeUnkeyedListEntry(UnkeyedListEntryNode node) throws IOException;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy