From 08c0f78336e6d48fc33ff5ab02c8e03ed975f134 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Fri, 5 Sep 2014 15:06:03 +0200 Subject: [PATCH] BUG-1704: rework state tracking In order to understand when a list (or container) is necessary, the state tracking machinery needs to be reworked. This patch does exactly that, adding a single-linked stack tracking nodes and their respective output. Change-Id: Iaf6ec6b25c05e0505a1dec6faad5fde2ecb791a0 Signed-off-by: Robert Varga --- .../gson/JSONNormalizedNodeStreamWriter.java | 219 +++--------------- .../codec/gson/JSONStreamWriterContext.java | 161 +++++++++++++ .../JSONStreamWriterInvisibleContext.java | 27 +++ .../gson/JSONStreamWriterListContext.java | 35 +++ .../JSONStreamWriterNamedObjectContext.java | 31 +++ .../gson/JSONStreamWriterObjectContext.java | 37 +++ .../gson/JSONStreamWriterQNameContext.java | 41 ++++ .../gson/JSONStreamWriterRootContext.java | 26 +++ .../gson/JSONStreamWriterURIContext.java | 37 +++ 9 files changed, 428 insertions(+), 186 deletions(-) create mode 100644 yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterContext.java create mode 100644 yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterInvisibleContext.java create mode 100644 yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterListContext.java create mode 100644 yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterNamedObjectContext.java create mode 100644 yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterObjectContext.java create mode 100644 yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterQNameContext.java create mode 100644 yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterRootContext.java create mode 100644 yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterURIContext.java 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 c7755b83bd..9e0224220e 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 @@ -17,9 +17,7 @@ import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URI; -import java.util.ArrayDeque; import java.util.Collection; -import java.util.Deque; import org.opendaylight.yangtools.concepts.Codec; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; @@ -28,9 +26,9 @@ 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.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; -import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaPath; @@ -42,51 +40,20 @@ import org.opendaylight.yangtools.yang.model.api.SchemaPath; * FIXME: rewrite this in terms of {@link JsonWriter}. */ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter { - - private static enum NodeType { - OBJECT, - LIST, - OTHER, - } - - private static class TypeInfo { - private boolean hasAtLeastOneChild = false; - private final NodeType type; - private final URI uri; - - public TypeInfo(final NodeType type, final URI uri) { - this.type = type; - this.uri = uri; - } - - public void setHasAtLeastOneChild(final boolean hasChildren) { - this.hasAtLeastOneChild = hasChildren; - } - - public NodeType getType() { - return type; - } - - public URI getNamespace() { - return uri; - } - - public boolean hasAtLeastOneChild() { - return hasAtLeastOneChild; - } - } - + /** + * 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 static final Collection> NUMERIC_CLASSES = ImmutableSet.>of(Byte.class, Short.class, Integer.class, Long.class, BigInteger.class, BigDecimal.class); - private final Deque stack = new ArrayDeque<>(); + private final SchemaContext schemaContext; - private final CodecFactory codecs; private final SchemaTracker tracker; + private final CodecFactory codecs; private final Writer writer; private final String indent; - - private int currentDepth = 0; - private URI currentNamespace; + private JSONStreamWriterContext context; private JSONNormalizedNodeStreamWriter(final SchemaContext schemaContext, final Writer writer, final int indentSize) { @@ -106,8 +73,7 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite } this.codecs = CodecFactory.create(schemaContext); this.tracker = SchemaTracker.create(schemaContext, path); - - this.currentNamespace = initialNs; + this.context = new JSONStreamWriterRootContext(initialNs); } /** @@ -125,10 +91,11 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite * Create a new stream writer, which writes to the specified {@link Writer}. * * @param schemaContext Schema context + * @param path Root schemapath * @param writer Output writer * @return A stream writer instance */ - public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final SchemaPath path,final Writer writer) { + public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final SchemaPath path, final Writer writer) { return new JSONNormalizedNodeStreamWriter(schemaContext, path, writer, null, 0); } @@ -136,11 +103,13 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite * Create a new stream writer, which writes to the specified {@link Writer}. * * @param schemaContext Schema context + * @param path Root schemapath * @param writer Output writer * @param initialNs Initial namespace * @return A stream writer instance */ - public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final SchemaPath path,final URI initialNs, final Writer writer) { + public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final SchemaPath path, + final URI initialNs, final Writer writer) { return new JSONNormalizedNodeStreamWriter(schemaContext, path, writer, initialNs, 0); } @@ -161,22 +130,15 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite final LeafSchemaNode schema = tracker.leafNode(name); final Codec codec = codecs.codecFor(schema.getType()); - separateElementFromPreviousElement(); - writeJsonIdentifier(name); - currentNamespace = stack.peek().getNamespace(); + context.emittingChild(schemaContext, writer, indent); + context.writeJsonIdentifier(schemaContext, writer, name.getNodeType()); writeValue(codec.serialize(value)); - separateNextSiblingsWithComma(); } @Override public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException { tracker.startLeafSet(name); - - separateElementFromPreviousElement(); - stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace())); - writeJsonIdentifier(name); - writeStartList(); - indentRight(); + context = new JSONStreamWriterListContext(context, name); } @Override @@ -184,87 +146,57 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite final LeafListSchemaNode schema = tracker.leafSetEntryNode(); final Codec codec = codecs.codecFor(schema.getType()); - separateElementFromPreviousElement(); + context.emittingChild(schemaContext, writer, indent); writeValue(codec.serialize(value)); - separateNextSiblingsWithComma(); } @Override public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException { - tracker.startContainerNode(name); - - separateElementFromPreviousElement(); - stack.push(new TypeInfo(NodeType.OBJECT, name.getNodeType().getNamespace())); - writeJsonIdentifier(name); - writeStartObject(); - indentRight(); + final ContainerSchemaNode schema = tracker.startContainerNode(name); + context = new JSONStreamWriterNamedObjectContext(context, name, schema.isPresenceContainer() || DEFAULT_EMIT_EMPTY_CONTAINERS); } @Override public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException { tracker.startList(name); - - separateElementFromPreviousElement(); - stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace())); - writeJsonIdentifier(name); - writeStartList(); - indentRight(); + context = new JSONStreamWriterListContext(context, name); } @Override public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException { tracker.startListItem(name); - - separateElementFromPreviousElement(); - stack.push(new TypeInfo(NodeType.OBJECT, name.getNodeType().getNamespace())); - writeStartObject(); - indentRight(); + context = new JSONStreamWriterObjectContext(context, name, DEFAULT_EMIT_EMPTY_CONTAINERS); } @Override public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException { tracker.startList(name); - - separateElementFromPreviousElement(); - stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace())); - writeJsonIdentifier(name); - writeStartList(); - indentRight(); + context = new JSONStreamWriterListContext(context, name); } @Override public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint) throws IOException { tracker.startListItem(identifier); - separateElementFromPreviousElement(); - stack.push(new TypeInfo(NodeType.OBJECT, identifier.getNodeType().getNamespace())); - - - writeStartObject(); - indentRight(); + context = new JSONStreamWriterObjectContext(context, identifier, DEFAULT_EMIT_EMPTY_CONTAINERS); } @Override public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException { tracker.startList(name); - - separateElementFromPreviousElement(); - stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace())); - writeJsonIdentifier(name); - writeStartList(); - indentRight(); + context = new JSONStreamWriterListContext(context, name); } @Override - public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException { + public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) { tracker.startChoiceNode(name); - handleInvisibleNode(name.getNodeType().getNamespace()); + context = new JSONStreamWriterInvisibleContext(context); } @Override - public void startAugmentationNode(final AugmentationIdentifier identifier) throws IllegalArgumentException { + public void startAugmentationNode(final AugmentationIdentifier identifier) { tracker.startAugmentationNode(identifier); - handleInvisibleNode(currentNamespace); + context = new JSONStreamWriterInvisibleContext(context); } @Override @@ -272,85 +204,15 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite final AnyXmlSchemaNode schema = tracker.anyxmlNode(name); // FIXME: should have a codec based on this :) - separateElementFromPreviousElement(); - writeJsonIdentifier(name); - currentNamespace = stack.peek().getNamespace(); + context.emittingChild(schemaContext, writer, indent); + context.writeJsonIdentifier(schemaContext, writer, name.getNodeType()); writeValue(value); - separateNextSiblingsWithComma(); } @Override public void endNode() throws IOException { tracker.endNode(); - - final TypeInfo t = stack.pop(); - switch (t.getType()) { - case LIST: - indentLeft(); - newLine(); - writer.append(']'); - break; - case OBJECT: - indentLeft(); - newLine(); - writer.append('}'); - break; - default: - break; - } - - currentNamespace = stack.isEmpty() ? null : stack.peek().getNamespace(); - separateNextSiblingsWithComma(); - } - - private void separateElementFromPreviousElement() throws IOException { - if (!stack.isEmpty() && stack.peek().hasAtLeastOneChild()) { - writer.append(','); - } - newLine(); - } - - private void newLine() throws IOException { - if (indent != null) { - writer.append('\n'); - - for (int i = 0; i < currentDepth; i++) { - writer.append(indent); - } - } - } - - private void separateNextSiblingsWithComma() { - if (!stack.isEmpty()) { - stack.peek().setHasAtLeastOneChild(true); - } - } - - /** - * Invisible nodes have to be also pushed to stack because of pairing of start*() and endNode() methods. Information - * about child existing (due to printing comma) has to be transfered to invisible node. - */ - private void handleInvisibleNode(final URI uri) { - TypeInfo typeInfo = new TypeInfo(NodeType.OTHER, uri); - typeInfo.setHasAtLeastOneChild(stack.peek().hasAtLeastOneChild()); - stack.push(typeInfo); - } - - private void writeStartObject() throws IOException { - writer.append('{'); - } - - private void writeStartList() throws IOException { - writer.append('['); - } - - private void writeModulName(final URI namespace) throws IOException { - if (this.currentNamespace == null || namespace != this.currentNamespace) { - Module module = schemaContext.findModuleByNamespaceAndRevision(namespace, null); - writer.append(module.getName()); - writer.append(':'); - currentNamespace = namespace; - } + context = context.endNode(schemaContext, writer, indent); } private void writeValue(final Object value) throws IOException { @@ -365,21 +227,6 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite } } - private void writeJsonIdentifier(final NodeIdentifier name) throws IOException { - writer.append('"'); - writeModulName(name.getNodeType().getNamespace()); - writer.append(name.getNodeType().getLocalName()); - writer.append("\":"); - } - - private void indentRight() { - currentDepth++; - } - - private void indentLeft() { - currentDepth--; - } - @Override public void flush() throws IOException { writer.flush(); diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterContext.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterContext.java new file mode 100644 index 0000000000..1a5181a578 --- /dev/null +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterContext.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2014 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.yangtools.yang.data.codec.gson; + +import com.google.common.base.Preconditions; + +import java.io.IOException; +import java.io.Writer; +import java.net.URI; + +import javax.annotation.Nonnull; + +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * Abstract base class for a single level of {@link JSONNormalizedNodeStreamWriter} + * recursion. Provides the base API towards the writer, which is then specialized + * by subclasses. + */ +abstract class JSONStreamWriterContext { + private final JSONStreamWriterContext parent; + private final boolean mandatory; + private final int depth; + private boolean emittedMyself = false; + private boolean haveChild = false; + + /** + * Construct a new context. + * + * @param parent Parent context, usually non-null. + * @param mandatory Mandatory flag. If set to true, the corresponding node + * will be emitted even if it has no children. + */ + protected JSONStreamWriterContext(final JSONStreamWriterContext parent, final boolean mandatory) { + this.mandatory = mandatory; + this.parent = parent; + + if (parent != null) { + depth = parent.depth + 1; + } else { + depth = 0; + } + } + + /** + * Write a JSON node identifier, optionally prefixing it with the module name + * corresponding to its namespace. + * + * @param schema Schema context + * @param writer Output writer + * @param qname Namespace/name tuple + * @throws IOException when the writer reports it + */ + protected final void writeJsonIdentifier(final SchemaContext schema, final Writer writer, final QName qname) throws IOException { + writer.append('"'); + + // Prepend module name if namespaces do not match + final URI ns = qname.getNamespace(); + if (!ns.equals(getNamespace())) { + final Module module = schema.findModuleByNamespaceAndRevision(ns, null); + Preconditions.checkArgument(module != null, "Could not find module for namespace {}", ns); + + writer.append(module.getName()); + writer.append(':'); + } + + writer.append(qname.getLocalName()); + writer.append("\":"); + } + + /** + * Return the namespace associated with current node. + * + * @return Namespace as URI + */ + protected abstract @Nonnull URI getNamespace(); + + /** + * Emit the start of an element. + * + * @param schema Schema context + * @param writer Output writer + * @throws IOException + */ + protected abstract void emitStart(final SchemaContext schema, final Writer writer) throws IOException; + + /** + * Emit the end of an element. + * + * @param schema Schema context + * @param writer Output writer + * @throws IOException + */ + protected abstract void emitEnd(final Writer writer) throws IOException; + + private final void emitMyself(final SchemaContext schema, final Writer writer, final String indent) throws IOException { + if (!emittedMyself) { + if (parent != null) { + parent.emittingChild(schema, writer, indent); + } + + emitStart(schema, writer); + emittedMyself = true; + } + } + + /** + * Invoked whenever a child node is being emitted. Checks whether this node has + * been emitted, and takes care of that if necessary. Also makes sure separator + * is emitted before a second and subsequent child. + * + * @param schema Schema context + * @param writer Output writer + * @param indent Indentation string + * @throws IOException when writer reports it + */ + final void emittingChild(final SchemaContext schema, final Writer writer, final String indent) throws IOException { + emitMyself(schema, writer, indent); + if (haveChild) { + writer.append(','); + } + + if (indent != null) { + writer.append('\n'); + + for (int i = 0; i < depth; i++) { + writer.append(indent); + } + } + haveChild = true; + } + + /** + * Invoked by the writer when it is leaving this node. Checks whether this node + * needs to be emitted and takes of that if necessary. + * + * @param schema Schema context + * @param writer Output writer + * @param indent Indentation string + * @return Parent node context + * @throws IOException when writer reports it + * @throws IllegalArgumentException if this node cannot be ended (e.g. root) + */ + final JSONStreamWriterContext endNode(final SchemaContext schema, final Writer writer, final String indent) throws IOException { + if (!emittedMyself && mandatory) { + emitMyself(schema, writer, indent); + } + + if (emittedMyself) { + emitEnd(writer); + } + return parent; + } +} diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterInvisibleContext.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterInvisibleContext.java new file mode 100644 index 0000000000..7f22c19466 --- /dev/null +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterInvisibleContext.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014 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.yangtools.yang.data.codec.gson; + +import com.google.common.base.Preconditions; + +import java.io.Writer; + +/** + * A virtual recursion level in {@link JSONNormalizedNodeStreamWriter}, used for nodes + * which are not emitted in the JSON representation. + */ +final class JSONStreamWriterInvisibleContext extends JSONStreamWriterURIContext { + JSONStreamWriterInvisibleContext(final JSONStreamWriterContext parent) { + super(Preconditions.checkNotNull(parent), parent.getNamespace()); + } + + @Override + protected void emitEnd(final Writer writer) { + // No-op + } +} \ No newline at end of file diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterListContext.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterListContext.java new file mode 100644 index 0000000000..ed7bd092c9 --- /dev/null +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterListContext.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 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.yangtools.yang.data.codec.gson; + +import com.google.common.base.Preconditions; +import java.io.IOException; +import java.io.Writer; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * A single recursion level of {@link JSONNormalizedNodeStreamWriter} representing + * a list. + */ +final class JSONStreamWriterListContext extends JSONStreamWriterQNameContext { + protected JSONStreamWriterListContext(final JSONStreamWriterContext parent, final NodeIdentifier id) { + super(Preconditions.checkNotNull(parent), id.getNodeType(), false); + } + + @Override + protected void emitStart(final SchemaContext schema, final Writer writer) throws IOException { + writeJsonIdentifier(schema, writer, getQName()); + writer.append('['); + } + + @Override + protected void emitEnd(final Writer writer) throws IOException { + writer.append(']'); + } +} diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterNamedObjectContext.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterNamedObjectContext.java new file mode 100644 index 0000000000..f5e5d48777 --- /dev/null +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterNamedObjectContext.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014 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.yangtools.yang.data.codec.gson; + +import java.io.IOException; +import java.io.Writer; + +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * A recursion level of {@link JSONNormalizedNodeStreamWriter}, which represents + * a JSON object which has to be prefixed with its identifier -- such as a + * container. + */ +final class JSONStreamWriterNamedObjectContext extends JSONStreamWriterObjectContext { + protected JSONStreamWriterNamedObjectContext(final JSONStreamWriterContext parent, final PathArgument arg, final boolean mandatory) { + super(parent, arg, mandatory); + } + + @Override + protected void emitStart(final SchemaContext schema, final Writer writer) throws IOException { + writeJsonIdentifier(schema, writer, getQName()); + super.emitStart(schema, writer); + } +} \ No newline at end of file diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterObjectContext.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterObjectContext.java new file mode 100644 index 0000000000..d12f0449dd --- /dev/null +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterObjectContext.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 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.yangtools.yang.data.codec.gson; + +import com.google.common.base.Preconditions; + +import java.io.IOException; +import java.io.Writer; + +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * A recursion level of {@link JSONNormalizedNodeStreamWriter}, which represents + * a JSON object which does not have to be prefixed with its identifier -- such + * as when it is in a containing list. + */ +class JSONStreamWriterObjectContext extends JSONStreamWriterQNameContext { + protected JSONStreamWriterObjectContext(final JSONStreamWriterContext parent, final PathArgument arg, final boolean mandatory) { + super(Preconditions.checkNotNull(parent), arg.getNodeType(), mandatory); + } + + @Override + protected void emitStart(final SchemaContext schema, final Writer writer) throws IOException { + writer.append('{'); + } + + @Override + protected void emitEnd(final Writer writer) throws IOException { + writer.append('}'); + } +} \ No newline at end of file diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterQNameContext.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterQNameContext.java new file mode 100644 index 0000000000..ad4ad6b986 --- /dev/null +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterQNameContext.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 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.yangtools.yang.data.codec.gson; + +import com.google.common.base.Preconditions; + +import java.net.URI; + +import org.opendaylight.yangtools.yang.common.QName; + +/** + * Abstract base class for {@link JSONNormalizedNodeStreamWriter} recursion + * levels which emit a QName-identified node. + */ +abstract class JSONStreamWriterQNameContext extends JSONStreamWriterContext { + private final QName qname; + + protected JSONStreamWriterQNameContext(final JSONStreamWriterContext parent, final QName qname, final boolean mandatory) { + super(parent, mandatory); + this.qname = Preconditions.checkNotNull(qname); + } + + /** + * Returns the node's identifier as a QName. + * + * @return QName identifier + */ + protected final QName getQName() { + return qname; + } + + @Override + protected final URI getNamespace() { + return qname.getNamespace(); + } +} \ No newline at end of file diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterRootContext.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterRootContext.java new file mode 100644 index 0000000000..36c3ff38c3 --- /dev/null +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterRootContext.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014 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.yangtools.yang.data.codec.gson; + +import java.io.Writer; +import java.net.URI; + +/** + * The root node of a particular {@link JSONNormalizedNodeStreamWriter} instance. + * It holds the base namespace and can never be removed from the stack. + */ +final class JSONStreamWriterRootContext extends JSONStreamWriterURIContext { + JSONStreamWriterRootContext(final URI namespace) { + super(null, namespace); + } + + @Override + protected void emitEnd(final Writer writer) { + throw new IllegalArgumentException("Top-level node reached"); + } +} diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterURIContext.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterURIContext.java new file mode 100644 index 0000000000..06c32bf26d --- /dev/null +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterURIContext.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 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.yangtools.yang.data.codec.gson; + +import java.io.IOException; +import java.io.Writer; +import java.net.URI; + +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * Abstract class tracking a virtual level of {@link JSONNormalizedNodeStreamWriter} + * recursion. It only tracks the namespace associated with this node. + */ +abstract class JSONStreamWriterURIContext extends JSONStreamWriterContext { + private final URI namespace; + + protected JSONStreamWriterURIContext(final JSONStreamWriterContext parent, final URI namespace) { + super(parent, false); + this.namespace = namespace; + } + + @Override + protected final URI getNamespace() { + return namespace; + } + + @Override + protected final void emitStart(final SchemaContext schema, final Writer writer) throws IOException { + // No-op + } +} \ No newline at end of file -- 2.36.6