Reimplement SchemaContextUtil.getBaseTypeForLeafRef()
[yangtools.git] / yang / yang-data-codec-xml / src / main / java / org / opendaylight / yangtools / yang / data / codec / xml / SchemaAwareXMLStreamNormalizedNodeStreamWriter.java
index dd0701fc6c0b6bce79dec13c6d0fa063a89dda64..f859479751f1a58a3681e4d58ff27cf94ab22006 100644 (file)
  */
 package org.opendaylight.yangtools.yang.data.codec.xml;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
 import java.io.IOException;
-import java.util.Collections;
-import java.util.Map;
-import javax.annotation.Nonnull;
+import java.util.Optional;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.dom.DOMSource;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.rfc7952.model.api.AnnotationSchemaNode;
 import org.opendaylight.yangtools.yang.common.QName;
 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.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-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.data.util.NormalizedNodeStreamWriterStack;
+import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 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;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 
-final class SchemaAwareXMLStreamNormalizedNodeStreamWriter extends XMLStreamNormalizedNodeStreamWriter<SchemaNode>
-        implements SchemaContextProvider {
-    private final SchemaTracker tracker;
+final class SchemaAwareXMLStreamNormalizedNodeStreamWriter
+        extends XMLStreamNormalizedNodeStreamWriter<TypedDataSchemaNode> implements EffectiveModelContextProvider {
+    private final NormalizedNodeStreamWriterStack tracker;
     private final SchemaAwareXMLStreamWriterUtils streamUtils;
 
-    private SchemaAwareXMLStreamNormalizedNodeStreamWriter(final XMLStreamWriter writer, final SchemaContext context,
-                                                           final SchemaPath path) {
+    SchemaAwareXMLStreamNormalizedNodeStreamWriter(final XMLStreamWriter writer, final EffectiveModelContext context,
+            final NormalizedNodeStreamWriterStack tracker) {
         super(writer);
-        this.tracker = SchemaTracker.create(context, path);
+        this.tracker = requireNonNull(tracker);
         this.streamUtils = new SchemaAwareXMLStreamWriterUtils(context);
     }
 
-    static NormalizedNodeStreamWriter newInstance(final XMLStreamWriter writer, final SchemaContext context,
-            final SchemaPath path) {
-        return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, path);
+    @Override
+    String encodeValue(final ValueWriter xmlWriter, final Object value, final TypedDataSchemaNode schemaNode)
+            throws XMLStreamException {
+        return streamUtils.encodeValue(xmlWriter, resolveType(schemaNode.getType()), value,
+            schemaNode.getQName().getModule());
     }
 
     @Override
-    protected void writeValue(final XMLStreamWriter xmlWriter, final QName qname, @Nonnull final Object value,
-            final SchemaNode schemaNode) throws IOException, XMLStreamException {
-        streamUtils.writeValue(xmlWriter, schemaNode, value, qname.getModule());
+    String encodeAnnotationValue(final ValueWriter xmlWriter, final QName qname, final Object value)
+            throws XMLStreamException {
+        final Optional<AnnotationSchemaNode> optAnnotation =
+            AnnotationSchemaNode.find(streamUtils.getEffectiveModelContext(), qname);
+        if (optAnnotation.isPresent()) {
+            return streamUtils.encodeValue(xmlWriter, resolveType(optAnnotation.get().getType()), value,
+                qname.getModule());
+        }
+
+        checkArgument(!qname.getRevision().isPresent(), "Failed to find bound annotation %s", qname);
+        checkArgument(value instanceof String, "Invalid non-string value %s for unbound annotation %s", value, qname);
+        return (String) value;
     }
 
     @Override
-    protected void startList(final NodeIdentifier name) {
+    void startList(final NodeIdentifier name) {
         tracker.startList(name);
     }
 
     @Override
-    protected void startListItem(final PathArgument name) throws IOException {
+    void startListItem(final PathArgument name) throws IOException {
         tracker.startListItem(name);
         startElement(name.getNodeType());
     }
 
     @Override
-    protected void endNode(final XMLStreamWriter xmlWriter) throws IOException, XMLStreamException {
+    public void endNode() throws IOException {
         final Object schema = tracker.endNode();
-        if (schema instanceof ListSchemaNode) {
+        if (schema instanceof ListSchemaNode || schema instanceof LeafListSchemaNode) {
             // For lists, we only emit end element on the inner frame
             final Object parent = tracker.getParent();
             if (parent == schema) {
-                xmlWriter.writeEndElement();
+                endElement();
             }
-        } else if (schema instanceof ContainerSchemaNode) {
-            // Emit container end element
-            xmlWriter.writeEndElement();
+        } else if (schema instanceof ContainerLike || schema instanceof LeafSchemaNode
+                || schema instanceof AnydataSchemaNode || schema instanceof AnyxmlSchemaNode) {
+            endElement();
         }
     }
 
     @Override
-    public void leafNode(final NodeIdentifier name, final Object value) throws IOException {
-        final LeafSchemaNode schema = tracker.leafNode(name);
-        writeElement(schema.getQName(), value, Collections.emptyMap(), schema);
-    }
-
-    @Override
-    public void leafNode(final NodeIdentifier name, final Object value, final Map<QName, String> attributes)
-        throws IOException {
-        final LeafSchemaNode schema = tracker.leafNode(name);
-        writeElement(schema.getQName(), value, attributes, schema);
-    }
-
-    @Override
-    public void leafSetEntryNode(final QName name, final Object value, final Map<QName, String> attributes)
-            throws IOException {
-        final LeafListSchemaNode schema = tracker.leafSetEntryNode(name);
-        writeElement(schema.getQName(), value, attributes, schema);
+    public void startLeafNode(final NodeIdentifier name) throws IOException {
+        tracker.startLeafNode(name);
+        startElement(name.getNodeType());
     }
 
     @Override
-    public void leafSetEntryNode(final QName name, final Object value) throws IOException {
-        final LeafListSchemaNode schema = tracker.leafSetEntryNode(name);
-        writeElement(schema.getQName(), value, Collections.emptyMap(), schema);
+    public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
+        tracker.startLeafSetEntryNode(name);
+        startElement(name.getNodeType());
     }
 
     @Override
@@ -132,19 +137,52 @@ final class SchemaAwareXMLStreamNormalizedNodeStreamWriter extends XMLStreamNorm
     }
 
     @Override
-    public void startYangModeledAnyXmlNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
-        final SchemaNode schema = tracker.startYangModeledAnyXmlNode(name);
-        startElement(schema.getQName());
+    public boolean startAnyxmlNode(final NodeIdentifier name, final Class<?> objectModel) throws IOException {
+        if (DOMSource.class.isAssignableFrom(objectModel)) {
+            tracker.startAnyxmlNode(name);
+            startElement(name.getNodeType());
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public EffectiveModelContext getEffectiveModelContext() {
+        return streamUtils.getEffectiveModelContext();
+    }
+
+    @Override
+    public void scalarValue(final Object value) throws IOException {
+        final Object current = tracker.getParent();
+        if (current instanceof TypedDataSchemaNode) {
+            writeValue(value, (TypedDataSchemaNode) current);
+        } else if (current instanceof AnydataSchemaNode) {
+            anydataValue(value);
+        } else {
+            throw new IllegalStateException("Unexpected scalar value " + value + " with " + current);
+        }
     }
 
     @Override
-    public void anyxmlNode(final NodeIdentifier name, final Object value) throws IOException {
-        final AnyXmlSchemaNode schema = tracker.anyxmlNode(name);
-        anyxmlNode(schema.getQName(), value);
+    public void domSourceValue(final DOMSource value) throws IOException {
+        final Object current = tracker.getParent();
+        checkState(current instanceof AnyxmlSchemaNode, "Unexpected scala value %s with %s", value, current);
+        anyxmlValue(value);
     }
 
     @Override
-    public SchemaContext getSchemaContext() {
-        return streamUtils.getSchemaContext();
+    void startAnydata(final NodeIdentifier name) {
+        tracker.startAnydataNode(name);
+    }
+
+    private @NonNull TypeDefinition<?> resolveType(final @NonNull TypeDefinition<?> type) throws XMLStreamException {
+        if (type instanceof LeafrefTypeDefinition) {
+            try {
+                return tracker.resolveLeafref((LeafrefTypeDefinition) type);
+            } catch (IllegalArgumentException e) {
+                throw new XMLStreamException("Cannot resolved type " + type, e);
+            }
+        }
+        return type;
     }
 }