X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-data-codec-gson%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Fcodec%2Fgson%2FJsonParserStream.java;h=e6f8dfdc4354a07576a4ee8fbb8bcecdd6e9753a;hb=5280e8d0efe5177e5bd9fa15bfd2bdc01e222d1b;hp=9b7c48fe61afae3d59d2a440583ed77ace8f1a0b;hpb=c8668229ad6e73d5ae03a52f4b87e8e4d2a67c6e;p=yangtools.git diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java index 9b7c48fe61..e6f8dfdc43 100644 --- a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java @@ -21,7 +21,6 @@ import java.io.Closeable; import java.io.EOFException; import java.io.Flushable; import java.io.IOException; -import java.net.URI; import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayDeque; import java.util.Deque; @@ -31,17 +30,18 @@ import java.util.Map.Entry; import java.util.Set; import javax.xml.transform.dom.DOMSource; import org.eclipse.jdt.annotation.NonNull; -import org.opendaylight.yangtools.odlext.model.api.YangModeledAnyxmlSchemaNode; import org.opendaylight.yangtools.util.xml.UntrustedXML; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.XMLNamespace; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; import org.opendaylight.yangtools.yang.data.util.AbstractNodeDataWithSchema; import org.opendaylight.yangtools.yang.data.util.AnyXmlNodeDataWithSchema; import org.opendaylight.yangtools.yang.data.util.CompositeNodeDataWithSchema; -import org.opendaylight.yangtools.yang.data.util.LeafListEntryNodeDataWithSchema; +import org.opendaylight.yangtools.yang.data.util.CompositeNodeDataWithSchema.ChildReusePolicy; import org.opendaylight.yangtools.yang.data.util.LeafListNodeDataWithSchema; import org.opendaylight.yangtools.yang.data.util.LeafNodeDataWithSchema; -import org.opendaylight.yangtools.yang.data.util.ListEntryNodeDataWithSchema; import org.opendaylight.yangtools.yang.data.util.ListNodeDataWithSchema; +import org.opendaylight.yangtools.yang.data.util.MultipleEntryDataWithSchema; import org.opendaylight.yangtools.yang.data.util.OperationAsContainer; import org.opendaylight.yangtools.yang.data.util.ParserStreamUtils; import org.opendaylight.yangtools.yang.data.util.SimpleNodeDataWithSchema; @@ -49,10 +49,12 @@ import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.OperationDefinition; -import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -68,20 +70,35 @@ public final class JsonParserStream implements Closeable, Flushable { static final String ANYXML_ARRAY_ELEMENT_ID = "array-element"; private static final Logger LOG = LoggerFactory.getLogger(JsonParserStream.class); - private final Deque namespaces = new ArrayDeque<>(); + private final Deque namespaces = new ArrayDeque<>(); private final NormalizedNodeStreamWriter writer; private final JSONCodecFactory codecs; private final DataSchemaNode parentNode; + private final SchemaInferenceStack stack; + // TODO: consider class specialization to remove this field private final boolean lenient; private JsonParserStream(final NormalizedNodeStreamWriter writer, final JSONCodecFactory codecs, - final DataSchemaNode parentNode, final boolean lenient) { + final SchemaInferenceStack stack, final boolean lenient) { this.writer = requireNonNull(writer); this.codecs = requireNonNull(codecs); - this.parentNode = parentNode; + this.stack = requireNonNull(stack); this.lenient = lenient; + + if (!stack.isEmpty()) { + final EffectiveStatement parent = stack.currentStatement(); + if (parent instanceof DataSchemaNode) { + parentNode = (DataSchemaNode) parent; + } else if (parent instanceof OperationDefinition) { + parentNode = OperationAsContainer.of((OperationDefinition) parent); + } else { + throw new IllegalArgumentException("Illegal parent node " + parent); + } + } else { + parentNode = stack.getEffectiveModelContext(); + } } /** @@ -96,7 +113,8 @@ public final class JsonParserStream implements Closeable, Flushable { */ public static @NonNull JsonParserStream create(final @NonNull NormalizedNodeStreamWriter writer, final @NonNull JSONCodecFactory codecFactory) { - return new JsonParserStream(writer, codecFactory, codecFactory.getSchemaContext(), false); + return new JsonParserStream(writer, codecFactory, + SchemaInferenceStack.of(codecFactory.getEffectiveModelContext()), false); } /** @@ -110,8 +128,8 @@ public final class JsonParserStream implements Closeable, Flushable { * @throws NullPointerException if any of the arguments are null */ public static @NonNull JsonParserStream create(final @NonNull NormalizedNodeStreamWriter writer, - final @NonNull JSONCodecFactory codecFactory, final @NonNull SchemaNode parentNode) { - return new JsonParserStream(writer, codecFactory, validateParent(parentNode), false); + final @NonNull JSONCodecFactory codecFactory, final @NonNull EffectiveStatementInference parentNode) { + return new JsonParserStream(writer, codecFactory, SchemaInferenceStack.ofInference(parentNode), false); } /** @@ -132,7 +150,8 @@ public final class JsonParserStream implements Closeable, Flushable { */ public static @NonNull JsonParserStream createLenient(final @NonNull NormalizedNodeStreamWriter writer, final @NonNull JSONCodecFactory codecFactory) { - return new JsonParserStream(writer, codecFactory, codecFactory.getSchemaContext(), true); + return new JsonParserStream(writer, codecFactory, + SchemaInferenceStack.of(codecFactory.getEffectiveModelContext()), true); } /** @@ -152,8 +171,8 @@ public final class JsonParserStream implements Closeable, Flushable { * @throws NullPointerException if any of the arguments are null */ public static @NonNull JsonParserStream createLenient(final @NonNull NormalizedNodeStreamWriter writer, - final @NonNull JSONCodecFactory codecFactory, final @NonNull SchemaNode parentNode) { - return new JsonParserStream(writer, codecFactory, validateParent(parentNode), true); + final @NonNull JSONCodecFactory codecFactory, final @NonNull EffectiveStatementInference parentNode) { + return new JsonParserStream(writer, codecFactory, SchemaInferenceStack.ofInference(parentNode), true); } public JsonParserStream parse(final JsonReader reader) { @@ -280,13 +299,11 @@ public final class JsonParserStream implements Closeable, Flushable { } while (in.hasNext()) { final String jsonElementName = in.nextName(); - DataSchemaNode parentSchema = parent.getSchema(); - if (parentSchema instanceof YangModeledAnyxmlSchemaNode) { - parentSchema = ((YangModeledAnyxmlSchemaNode) parentSchema).getSchemaOfAnyXmlData(); - } - final Entry namespaceAndName = resolveNamespace(jsonElementName, parentSchema); + final DataSchemaNode parentSchema = parent.getSchema(); + final Entry namespaceAndName = + resolveNamespace(jsonElementName, parentSchema); final String localName = namespaceAndName.getKey(); - final URI namespace = namespaceAndName.getValue(); + final XMLNamespace namespace = namespaceAndName.getValue(); if (lenient && (localName == null || namespace == null)) { LOG.debug("Schema node with name {} was not found under {}", localName, parentSchema.getQName()); @@ -303,15 +320,17 @@ public final class JsonParserStream implements Closeable, Flushable { getCurrentNamespace()); checkState(!childDataSchemaNodes.isEmpty(), "Schema for node with name %s and namespace %s does not exist at %s", - localName, getCurrentNamespace(), parentSchema.getPath()); - + localName, getCurrentNamespace(), parentSchema); + final QName qname = childDataSchemaNodes.peekLast().getQName(); final AbstractNodeDataWithSchema newChild = ((CompositeNodeDataWithSchema) parent) - .addChild(childDataSchemaNodes); + .addChild(childDataSchemaNodes, ChildReusePolicy.NOOP); if (newChild instanceof AnyXmlNodeDataWithSchema) { readAnyXmlValue(in, (AnyXmlNodeDataWithSchema) newChild, jsonElementName); } else { + stack.enterDataTree(qname); read(in, newChild); + stack.exit(); } removeNamespace(); } @@ -327,16 +346,10 @@ public final class JsonParserStream implements Closeable, Flushable { } private static AbstractNodeDataWithSchema newArrayEntry(final AbstractNodeDataWithSchema parent) { - AbstractNodeDataWithSchema newChild; - if (parent instanceof ListNodeDataWithSchema) { - newChild = ListEntryNodeDataWithSchema.forSchema(((ListNodeDataWithSchema) parent).getSchema()); - } else if (parent instanceof LeafListNodeDataWithSchema) { - newChild = new LeafListEntryNodeDataWithSchema(((LeafListNodeDataWithSchema) parent).getSchema()); - } else { + if (!(parent instanceof MultipleEntryDataWithSchema)) { throw new IllegalStateException("Found an unexpected array nested under " + parent.getSchema().getQName()); } - ((CompositeNodeDataWithSchema) parent).addChild(newChild); - return newChild; + return ((MultipleEntryDataWithSchema) parent).newChildEntry(); } private void setValue(final AbstractNodeDataWithSchema parent, final String value) { @@ -352,34 +365,35 @@ public final class JsonParserStream implements Closeable, Flushable { private Object translateValueByType(final String value, final DataSchemaNode node) { checkArgument(node instanceof TypedDataSchemaNode); - return codecs.codecFor((TypedDataSchemaNode) node).parseValue(null, value); + return codecs.codecFor((TypedDataSchemaNode) node, stack).parseValue(null, value); } private void removeNamespace() { namespaces.pop(); } - private void addNamespace(final URI namespace) { + private void addNamespace(final XMLNamespace namespace) { namespaces.push(namespace); } - private Entry resolveNamespace(final String childName, final DataSchemaNode dataSchemaNode) { + private Entry resolveNamespace(final String childName, final DataSchemaNode dataSchemaNode) { final int lastIndexOfColon = childName.lastIndexOf(':'); String moduleNamePart = null; String nodeNamePart = null; - URI namespace = null; + XMLNamespace namespace = null; if (lastIndexOfColon != -1) { moduleNamePart = childName.substring(0, lastIndexOfColon); nodeNamePart = childName.substring(lastIndexOfColon + 1); - final Iterator m = codecs.getSchemaContext().findModules(moduleNamePart).iterator(); + final Iterator m = codecs.getEffectiveModelContext().findModules(moduleNamePart) + .iterator(); namespace = m.hasNext() ? m.next().getNamespace() : null; } else { nodeNamePart = childName; } if (namespace == null) { - final Set potentialUris = resolveAllPotentialNamespaces(nodeNamePart, dataSchemaNode); + final Set potentialUris = resolveAllPotentialNamespaces(nodeNamePart, dataSchemaNode); if (potentialUris.contains(getCurrentNamespace())) { namespace = getCurrentNamespace(); } else if (potentialUris.size() == 1) { @@ -396,18 +410,19 @@ public final class JsonParserStream implements Closeable, Flushable { return new SimpleImmutableEntry<>(nodeNamePart, namespace); } - private String toModuleNames(final Set potentialUris) { + private String toModuleNames(final Set potentialUris) { final StringBuilder builder = new StringBuilder(); - for (final URI potentialUri : potentialUris) { + for (final XMLNamespace potentialUri : potentialUris) { builder.append('\n'); //FIXME how to get information about revision from JSON input? currently first available is used. - builder.append(codecs.getSchemaContext().findModules(potentialUri).iterator().next().getName()); + builder.append(codecs.getEffectiveModelContext().findModules(potentialUri).iterator().next().getName()); } return builder.toString(); } - private Set resolveAllPotentialNamespaces(final String elementName, final DataSchemaNode dataSchemaNode) { - final Set potentialUris = new HashSet<>(); + private Set resolveAllPotentialNamespaces(final String elementName, + final DataSchemaNode dataSchemaNode) { + final Set potentialUris = new HashSet<>(); final Set choices = new HashSet<>(); if (dataSchemaNode instanceof DataNodeContainer) { for (final DataSchemaNode childSchemaNode : ((DataNodeContainer) dataSchemaNode).getChildNodes()) { @@ -419,7 +434,7 @@ public final class JsonParserStream implements Closeable, Flushable { } for (final ChoiceSchemaNode choiceNode : choices) { - for (final CaseSchemaNode concreteCase : choiceNode.getCases().values()) { + for (final CaseSchemaNode concreteCase : choiceNode.getCases()) { potentialUris.addAll(resolveAllPotentialNamespaces(elementName, concreteCase)); } } @@ -427,20 +442,10 @@ public final class JsonParserStream implements Closeable, Flushable { return potentialUris; } - private URI getCurrentNamespace() { + private XMLNamespace getCurrentNamespace() { return namespaces.peek(); } - private static DataSchemaNode validateParent(final SchemaNode parent) { - if (parent instanceof DataSchemaNode) { - return (DataSchemaNode) parent; - } else if (parent instanceof OperationDefinition) { - return OperationAsContainer.of((OperationDefinition) parent); - } else { - throw new IllegalArgumentException("Illegal parent node " + requireNonNull(parent)); - } - } - @Override public void flush() throws IOException { writer.flush();