*/
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
}
@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;
}
}