X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=inline;f=yang%2Fyang-data-codec-gson%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Fcodec%2Fgson%2FJSONNormalizedNodeStreamWriter.java;h=b8e574f2becbafde033e821eb794bf90d9e8c835;hb=8f3afc2f8e13d71f7e79c5bbea5b21e1c191de70;hp=57204c838aba86eee96f3f675090c8b9bb03d5bd;hpb=c5bde84eced27e2d073554420c3f47eca85af32c;p=yangtools.git 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 57204c838a..b8e574f2be 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 @@ -7,152 +7,225 @@ */ package org.opendaylight.yangtools.yang.data.codec.gson; -import com.google.common.base.Preconditions; +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.ImmutableClassToInstanceMap; import com.google.gson.stream.JsonWriter; import java.io.IOException; -import java.io.Writer; -import java.net.URI; +import java.util.NoSuchElementException; +import java.util.regex.Pattern; +import javax.xml.transform.dom.DOMSource; +import org.checkerframework.checker.regex.qual.Regex; +import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext; +import org.opendaylight.yangtools.rfc8528.data.api.MountPointIdentifier; +import org.opendaylight.yangtools.rfc8528.data.api.StreamWriterMountPointExtension; +import org.opendaylight.yangtools.yang.common.XMLNamespace; 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.schema.NormalizedAnydata; 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.LeafListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriterExtension; +import org.opendaylight.yangtools.yang.data.util.NormalizedNodeInferenceStack; +import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference; import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; +import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; /** * This implementation will create JSON output as output stream. * + *
* Values of leaf and leaf-list are NOT translated according to codecs. - * */ -public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter { +public abstract class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter, + StreamWriterMountPointExtension { + private static final class Exclusive extends JSONNormalizedNodeStreamWriter { + Exclusive(final JSONCodecFactory codecFactory, final NormalizedNodeInferenceStack tracker, + final JsonWriter writer, final JSONStreamWriterRootContext rootContext) { + super(codecFactory, tracker, writer, rootContext); + } + + @Override + public void close() throws IOException { + flush(); + closeWriter(); + } + } + + private static final class Nested extends JSONNormalizedNodeStreamWriter { + Nested(final JSONCodecFactory codecFactory, final NormalizedNodeInferenceStack tracker, final JsonWriter writer, + final JSONStreamWriterRootContext rootContext) { + super(codecFactory, tracker, writer, rootContext); + } + + @Override + public void close() throws IOException { + flush(); + // The caller "owns" the writer, let them close it + } + } + /** * RFC6020 deviation: we are not required to emit empty containers unless they * are marked as 'presence'. */ private static final boolean DEFAULT_EMIT_EMPTY_CONTAINERS = true; - private final SchemaTracker tracker; + @Regex + private static final String NUMBER_STRING = "-?\\d+(\\.\\d+)?"; + private static final Pattern NUMBER_PATTERN = Pattern.compile(NUMBER_STRING); + + @Regex + private static final String NOT_DECIMAL_NUMBER_STRING = "-?\\d+"; + private static final Pattern NOT_DECIMAL_NUMBER_PATTERN = Pattern.compile(NOT_DECIMAL_NUMBER_STRING); + + private final NormalizedNodeInferenceStack tracker; private final JSONCodecFactory codecs; private final JsonWriter writer; private JSONStreamWriterContext context; - private JSONNormalizedNodeStreamWriter(final JSONCodecFactory codecFactory, final SchemaPath path, JsonWriter JsonWriter, JSONStreamWriterRootContext rootContext) { - this.writer = Preconditions.checkNotNull(JsonWriter); - this.codecs = Preconditions.checkNotNull(codecFactory); - this.tracker = SchemaTracker.create(codecFactory.getSchemaContext(), path); - this.context = Preconditions.checkNotNull(rootContext); + JSONNormalizedNodeStreamWriter(final JSONCodecFactory codecFactory, final NormalizedNodeInferenceStack tracker, + final JsonWriter writer, final JSONStreamWriterRootContext rootContext) { + this.writer = requireNonNull(writer); + this.codecs = requireNonNull(codecFactory); + this.tracker = requireNonNull(tracker); + this.context = requireNonNull(rootContext); } /** - * Create a new stream writer, which writes to the specified {@link Writer}. + * Create a new stream writer, which writes to the specified output stream. * - * This instance of writer can be used only to emit one top level element, - * therwise it will produce incorrect JSON. + *
+ * The codec factory can be reused between multiple writers. * - * @param schemaContext Schema context - * @param writer Output writer - * @return A stream writer instance - */ - public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final Writer writer) { - return create(schemaContext, SchemaPath.ROOT, null, writer); - } - - /** - * Create a new stream writer, which writes to the specified {@link Writer}. + *
+ * 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, - * therwise it will produce incorrect JSON. + * otherwise it will produce incorrect JSON. Closing this instance will close + * the writer too. * - * @param schemaContext Schema context - * @param path Root schemapath - * @param writer Output writer + * @param codecFactory JSON codec factory + * @param path Schema Path + * @param initialNs Initial namespace + * @param jsonWriter JsonWriter * @return A stream writer instance */ - public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final SchemaPath path, final Writer writer) { - return create(schemaContext, path, null, writer); + public static NormalizedNodeStreamWriter createExclusiveWriter(final JSONCodecFactory codecFactory, + final SchemaPath path, final XMLNamespace initialNs, final JsonWriter jsonWriter) { + return new Exclusive(codecFactory, + NormalizedNodeInferenceStack.of(codecFactory.getEffectiveModelContext(), path), jsonWriter, + new JSONStreamWriterExclusiveRootContext(initialNs)); } /** - * Create a new stream writer, which writes to the specified {@link Writer}. + * 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, - * therwise it will produce incorrect JSON. + * otherwise it will produce incorrect JSON. Closing this instance will close + * the writer too. * - * @param schemaContext Schema context - * @param path Root schemapath - * @param writer Output writer + * @param codecFactory JSON codec factory + * @param rootNode Root node inference * @param initialNs Initial namespace + * @param jsonWriter JsonWriter * @return A stream writer instance */ - public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final SchemaPath path, - final URI initialNs, final Writer writer) { - return createExclusiveWriter(JSONCodecFactory.create(schemaContext), path, initialNs, JsonWriterFactory.createJsonWriter(writer)); + public static NormalizedNodeStreamWriter createExclusiveWriter(final JSONCodecFactory codecFactory, + final EffectiveStatementInference rootNode, final XMLNamespace initialNs, final JsonWriter jsonWriter) { + return new Exclusive(codecFactory, NormalizedNodeInferenceStack.of(rootNode), jsonWriter, + new JSONStreamWriterExclusiveRootContext(initialNs)); } /** * Create a new stream writer, which writes to the specified output stream. * - * This instance of writer can be used only to emit one top level element, - * therwise it will produce incorrect JSON. + *
+ * The codec factory can be reused between multiple writers. * - * @param schemaContext Schema context - * @param writer Output writer - * @param indentSize indentation size - * @return A stream writer instance - */ - public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final Writer writer, final int indentSize) { - return createExclusiveWriter(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, null,JsonWriterFactory.createJsonWriter(writer, indentSize)); - } - - /** - * 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, - * therwise it will produce incorrect JSON. + * otherwise it will produce incorrect JSON. Closing this instance will close + * the writer too. * * @param codecFactory JSON codec factory - * @param writer Output writer - * @param indentSize indentation size + * @param path Schema Path + * @param initialNs Initial namespace + * @param jsonWriter JsonWriter * @return A stream writer instance */ - public static NormalizedNodeStreamWriter create(final JSONCodecFactory codecFactory, final Writer writer, final int indentSize) { - return createExclusiveWriter(codecFactory, SchemaPath.ROOT, null, JsonWriterFactory.createJsonWriter(writer,indentSize)); + public static NormalizedNodeStreamWriter createExclusiveWriter(final JSONCodecFactory codecFactory, + final Absolute path, final XMLNamespace initialNs, final JsonWriter jsonWriter) { + return new Exclusive(codecFactory, + NormalizedNodeInferenceStack.of(codecFactory.getEffectiveModelContext(), path), jsonWriter, + new JSONStreamWriterExclusiveRootContext(initialNs)); } /** * Create a new stream writer, which writes to the specified output stream. * - * This instance of writer can be used only to emit one top level element, - * therwise it will produce incorrect JSON. + *
+ * The codec factory can be reused between multiple writers. * - * @param schemaContext Schema context + *
+ * 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 path Schema Path * @param initialNs Initial namespace * @param jsonWriter JsonWriter * @return A stream writer instance */ - public static NormalizedNodeStreamWriter create(SchemaContext schemaContext, SchemaPath path, URI initialNs, - JsonWriter jsonWriter) { - return createExclusiveWriter(JSONCodecFactory.create(schemaContext), path, initialNs, jsonWriter); + public static NormalizedNodeStreamWriter createNestedWriter(final JSONCodecFactory codecFactory, + final SchemaPath path, final XMLNamespace initialNs, final JsonWriter jsonWriter) { + return new Nested(codecFactory, NormalizedNodeInferenceStack.of(codecFactory.getEffectiveModelContext(), 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 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, - * therwise it will produce incorrect JSON. + *
+ * 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 path Schema Path @@ -160,152 +233,346 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite * @param jsonWriter JsonWriter * @return A stream writer instance */ - public static NormalizedNodeStreamWriter createExclusiveWriter(JSONCodecFactory codecFactory, SchemaPath path, URI initialNs, JsonWriter jsonWriter) { - return new JSONNormalizedNodeStreamWriter(codecFactory, path, jsonWriter, new JSONStreamWriterExclusiveRootContext(initialNs)); + public static NormalizedNodeStreamWriter createNestedWriter(final JSONCodecFactory codecFactory, + final Absolute path, final XMLNamespace initialNs, final JsonWriter jsonWriter) { + return new Nested(codecFactory, NormalizedNodeInferenceStack.of(codecFactory.getEffectiveModelContext(), 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. + * 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 path Schema Path + * @param rootNode Root node inference * @param initialNs Initial namespace * @param jsonWriter JsonWriter * @return A stream writer instance */ - public static NormalizedNodeStreamWriter createNestedWriter(JSONCodecFactory codecFactory, SchemaPath path, URI initialNs, JsonWriter jsonWriter) { - return new JSONNormalizedNodeStreamWriter(codecFactory, path, jsonWriter, new JSONStreamWriterSharedRootContext(initialNs)); + public static NormalizedNodeStreamWriter createNestedWriter(final JSONCodecFactory codecFactory, + final EffectiveStatementInference rootNode, final XMLNamespace initialNs, final JsonWriter jsonWriter) { + return new Nested(codecFactory, NormalizedNodeInferenceStack.of(rootNode), jsonWriter, + new JSONStreamWriterSharedRootContext(initialNs)); } @Override - public void leafNode(final NodeIdentifier name, final Object value) throws IOException { - final LeafSchemaNode schema = tracker.leafNode(name); - final JSONCodec