From 57b893fcb28a5955d308da8e4a19785422075ebf Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Sun, 20 Jan 2019 19:43:42 +0100 Subject: [PATCH] Allow JSON/XML writers to be instantiated with root node Rather than requiring a SchemaContext/SchemaPath combination, allow writers to be instantiated by specifying a DataNodeContainer. Change-Id: I9eb470587cad2af9b3390d134dcc03abc95e8645 JIRA: YANGTOOLS-935 Signed-off-by: Robert Varga (cherry picked from commit aa37f2a86bfb4d04a99f78b1b0d892b3c0b76caf) --- .../gson/JSONNormalizedNodeStreamWriter.java | 73 ++++++++++++++++--- ...reXMLStreamNormalizedNodeStreamWriter.java | 7 +- .../XMLStreamNormalizedNodeStreamWriter.java | 23 +++++- .../yang/data/impl/codec/SchemaTracker.java | 46 ++++++++---- 4 files changed, 117 insertions(+), 32 deletions(-) diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java index 6311b7ce54..67283655db 100644 --- a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java @@ -24,6 +24,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; import org.opendaylight.yangtools.yang.data.impl.codec.SchemaTracker; import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaNode; @@ -41,9 +42,9 @@ import org.w3c.dom.Text; */ public abstract class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter { private static final class Exclusive extends JSONNormalizedNodeStreamWriter { - Exclusive(final JSONCodecFactory codecFactory, final SchemaPath path, final JsonWriter writer, + Exclusive(final JSONCodecFactory codecFactory, final SchemaTracker tracker, final JsonWriter writer, final JSONStreamWriterRootContext rootContext) { - super(codecFactory, path, writer, rootContext); + super(codecFactory, tracker, writer, rootContext); } @Override @@ -54,9 +55,9 @@ public abstract class JSONNormalizedNodeStreamWriter implements NormalizedNodeSt } private static final class Nested extends JSONNormalizedNodeStreamWriter { - Nested(final JSONCodecFactory codecFactory, final SchemaPath path, final JsonWriter writer, + Nested(final JSONCodecFactory codecFactory, final SchemaTracker tracker, final JsonWriter writer, final JSONStreamWriterRootContext rootContext) { - super(codecFactory, path, writer, rootContext); + super(codecFactory, tracker, writer, rootContext); } @Override @@ -85,11 +86,11 @@ public abstract class JSONNormalizedNodeStreamWriter implements NormalizedNodeSt private final JsonWriter writer; private JSONStreamWriterContext context; - JSONNormalizedNodeStreamWriter(final JSONCodecFactory codecFactory, final SchemaPath path, final JsonWriter writer, - final JSONStreamWriterRootContext rootContext) { + JSONNormalizedNodeStreamWriter(final JSONCodecFactory codecFactory, final SchemaTracker tracker, + final JsonWriter writer, final JSONStreamWriterRootContext rootContext) { this.writer = requireNonNull(writer); this.codecs = requireNonNull(codecFactory); - this.tracker = SchemaTracker.create(codecFactory.getSchemaContext(), path); + this.tracker = requireNonNull(tracker); this.context = requireNonNull(rootContext); } @@ -116,7 +117,35 @@ public abstract class JSONNormalizedNodeStreamWriter implements NormalizedNodeSt */ public static NormalizedNodeStreamWriter createExclusiveWriter(final JSONCodecFactory codecFactory, final SchemaPath path, final URI initialNs, final JsonWriter jsonWriter) { - return new Exclusive(codecFactory, path, jsonWriter, new JSONStreamWriterExclusiveRootContext(initialNs)); + return new Exclusive(codecFactory, SchemaTracker.create(codecFactory.getSchemaContext(), path), jsonWriter, + new JSONStreamWriterExclusiveRootContext(initialNs)); + } + + /** + * Create a new stream writer, which writes to the specified output stream. + * + *

+ * The codec factory can be reused between multiple writers. + * + *

+ * Returned writer is exclusive user of JsonWriter, which means it will start + * top-level JSON element and ends it. + * + *

+ * This instance of writer can be used only to emit one top level element, + * otherwise it will produce incorrect JSON. Closing this instance will close + * the writer too. + * + * @param codecFactory JSON codec factory + * @param rootNode Root node + * @param initialNs Initial namespace + * @param jsonWriter JsonWriter + * @return A stream writer instance + */ + public static NormalizedNodeStreamWriter createExclusiveWriter(final JSONCodecFactory codecFactory, + final DataNodeContainer rootNode, final URI initialNs, final JsonWriter jsonWriter) { + return new Exclusive(codecFactory, SchemaTracker.create(rootNode), jsonWriter, + new JSONStreamWriterExclusiveRootContext(initialNs)); } /** @@ -140,7 +169,33 @@ public abstract class JSONNormalizedNodeStreamWriter implements NormalizedNodeSt */ public static NormalizedNodeStreamWriter createNestedWriter(final JSONCodecFactory codecFactory, final SchemaPath path, final URI initialNs, final JsonWriter jsonWriter) { - return new Nested(codecFactory, path, jsonWriter, new JSONStreamWriterSharedRootContext(initialNs)); + return new Nested(codecFactory, SchemaTracker.create(codecFactory.getSchemaContext(), path), jsonWriter, + new JSONStreamWriterSharedRootContext(initialNs)); + } + + /** + * Create a new stream writer, which writes to the specified output stream. + * + *

+ * The codec factory can be reused between multiple writers. + * + *

+ * Returned writer can be used emit multiple top level element, + * but does not start / close parent JSON object, which must be done + * by user providing {@code jsonWriter} instance in order for + * JSON to be valid. Closing this instance will not + * close the wrapped writer; the caller must take care of that. + * + * @param codecFactory JSON codec factory + * @param rootNode Root node + * @param initialNs Initial namespace + * @param jsonWriter JsonWriter + * @return A stream writer instance + */ + public static NormalizedNodeStreamWriter createNestedWriter(final JSONCodecFactory codecFactory, + final DataNodeContainer rootNode, final URI initialNs, final JsonWriter jsonWriter) { + return new Nested(codecFactory, SchemaTracker.create(rootNode), jsonWriter, + new JSONStreamWriterSharedRootContext(initialNs)); } @Override diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/SchemaAwareXMLStreamNormalizedNodeStreamWriter.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/SchemaAwareXMLStreamNormalizedNodeStreamWriter.java index 31d44c0a6c..51f1742df5 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/SchemaAwareXMLStreamNormalizedNodeStreamWriter.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/SchemaAwareXMLStreamNormalizedNodeStreamWriter.java @@ -8,6 +8,8 @@ */ package org.opendaylight.yangtools.yang.data.codec.xml; +import static java.util.Objects.requireNonNull; + import java.io.IOException; import java.util.Collections; import java.util.Map; @@ -26,7 +28,6 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider; import org.opendaylight.yangtools.yang.model.api.SchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; final class SchemaAwareXMLStreamNormalizedNodeStreamWriter extends XMLStreamNormalizedNodeStreamWriter implements SchemaContextProvider { @@ -34,9 +35,9 @@ final class SchemaAwareXMLStreamNormalizedNodeStreamWriter extends XMLStreamNorm private final SchemaAwareXMLStreamWriterUtils streamUtils; SchemaAwareXMLStreamNormalizedNodeStreamWriter(final XMLStreamWriter writer, final SchemaContext context, - final SchemaPath path) { + final SchemaTracker tracker) { super(writer); - this.tracker = SchemaTracker.create(context, path); + this.tracker = requireNonNull(tracker); this.streamUtils = new SchemaAwareXMLStreamWriterUtils(context); } diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java index 55e4e93b24..bc38a6c692 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java @@ -38,6 +38,8 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamAttributeWriter; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.impl.codec.SchemaTracker; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.slf4j.Logger; @@ -89,8 +91,22 @@ public abstract class XMLStreamNormalizedNodeStreamWriter implements Normaliz * @param context Associated {@link SchemaContext}. * @return A new {@link NormalizedNodeStreamWriter} */ - public static NormalizedNodeStreamWriter create(final XMLStreamWriter writer, final SchemaContext context) { - return create(writer, context, SchemaPath.ROOT); + public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer, + final SchemaContext context) { + return create(writer, context, context); + } + + /** + * Create a new writer with the specified context and rooted at the specified node. + * + * @param writer Output {@link XMLStreamWriter} + * @param context Associated {@link SchemaContext}. + * @param rootNode Root node + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer, final SchemaContext context, + final DataNodeContainer rootNode) { + return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, SchemaTracker.create(rootNode)); } /** @@ -99,12 +115,11 @@ public abstract class XMLStreamNormalizedNodeStreamWriter implements Normaliz * @param writer Output {@link XMLStreamWriter} * @param context Associated {@link SchemaContext}. * @param path path - * * @return A new {@link NormalizedNodeStreamWriter} */ public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer, final SchemaContext context, final SchemaPath path) { - return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, path); + return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, SchemaTracker.create(context, path)); } /** diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java index 4f531089b2..7a9bd4c906 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java @@ -8,6 +8,7 @@ package org.opendaylight.yangtools.yang.data.impl.codec; import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.collect.Iterables; @@ -16,6 +17,7 @@ import java.util.ArrayDeque; import java.util.Collection; import java.util.Deque; import java.util.Optional; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.odlext.model.api.YangModeledAnyXmlSchemaNode; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; @@ -53,18 +55,8 @@ public final class SchemaTracker { private final Deque schemaStack = new ArrayDeque<>(); private final DataNodeContainer root; - private SchemaTracker(final SchemaContext context, final SchemaPath path) { - final Collection schemaNodes = SchemaUtils.findParentSchemaNodesOnPath(context, path); - checkArgument(!schemaNodes.isEmpty(), "Unable to find schema node for supplied schema path: %s", path); - if (schemaNodes.size() > 1) { - LOG.warn("More possible schema nodes {} for supplied schema path {}", schemaNodes, path); - } - final Optional current = schemaNodes.stream().filter(node -> node instanceof DataNodeContainer) - .findFirst(); - checkArgument(current.isPresent(), - "Schema path must point to container or list or an rpc input/output. Supplied path %s pointed to: %s", - path, current); - root = (DataNodeContainer) current.get(); + private SchemaTracker(final DataNodeContainer root) { + this.root = requireNonNull(root); } /** @@ -73,8 +65,19 @@ public final class SchemaTracker { * @param context Associated {@link SchemaContext}. * @return A new {@link NormalizedNodeStreamWriter} */ - public static SchemaTracker create(final SchemaContext context) { - return create(context, SchemaPath.ROOT); + // FIXME: 3.0.0: remove this method + public static @NonNull SchemaTracker create(final SchemaContext context) { + return new SchemaTracker(context); + } + + /** + * Create a new writer with the specified node as its root. + * + * @param root Root node + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull SchemaTracker create(final DataNodeContainer root) { + return new SchemaTracker(root); } /** @@ -84,8 +87,19 @@ public final class SchemaTracker { * @param path schema path * @return A new {@link NormalizedNodeStreamWriter} */ - public static SchemaTracker create(final SchemaContext context, final SchemaPath path) { - return new SchemaTracker(context, path); + public static @NonNull SchemaTracker create(final SchemaContext context, final SchemaPath path) { + final Collection schemaNodes = SchemaUtils.findParentSchemaNodesOnPath(context, path); + checkArgument(!schemaNodes.isEmpty(), "Unable to find schema node for supplied schema path: %s", path); + if (schemaNodes.size() > 1) { + LOG.warn("More possible schema nodes {} for supplied schema path {}", schemaNodes, path); + } + final Optional current = schemaNodes.stream() + .filter(node -> node instanceof DataNodeContainer).map(DataNodeContainer.class::cast) + .findFirst(); + checkArgument(current.isPresent(), + "Schema path must point to container or list or an rpc input/output. Supplied path %s pointed to: %s", + path, current); + return new SchemaTracker(current.get()); } public Object getParent() { -- 2.36.6