import static java.util.Objects.requireNonNull;
-import com.google.common.base.Preconditions;
import java.io.IOException;
import java.util.AbstractMap;
import java.util.ArrayDeque;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.transform.dom.DOMSource;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.concepts.Delegator;
import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.Identifiable;
-import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.Key;
+import org.opendaylight.yangtools.yang.binding.KeyAware;
+import org.opendaylight.yangtools.yang.binding.OpaqueObject;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-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.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-final class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, Delegator<NormalizedNodeStreamWriter> {
- private final Deque<NodeCodecContext<?>> schema = new ArrayDeque<>();
- private final NormalizedNodeStreamWriter delegate;
- private final NodeCodecContext<?> rootNodeSchema;
+final class BindingToNormalizedStreamWriter implements AnydataBindingStreamWriter,
+ Delegator<NormalizedNodeStreamWriter> {
+ private final Deque<CodecContext> schema = new ArrayDeque<>();
+ private final @NonNull NormalizedNodeStreamWriter delegate;
+ private final CodecContext rootContext;
- BindingToNormalizedStreamWriter(final NodeCodecContext<?> rootNodeSchema,
+ BindingToNormalizedStreamWriter(final DataContainerCodecContext<?, ?, ?> rootContext,
final NormalizedNodeStreamWriter delegate) {
- this.rootNodeSchema = requireNonNull(rootNodeSchema);
+ this.rootContext = requireNonNull(rootContext);
this.delegate = requireNonNull(delegate);
}
- static BindingToNormalizedStreamWriter create(final NodeCodecContext<?> schema,
- final NormalizedNodeStreamWriter delegate) {
- return new BindingToNormalizedStreamWriter(schema, delegate);
- }
-
private void emitSchema(final Object schemaNode) {
delegate.nextDataSchemaNode((DataSchemaNode) schemaNode);
}
- NodeCodecContext<?> current() {
+ CodecContext current() {
return schema.peek();
}
private NodeIdentifier duplicateSchemaEnter() {
- final NodeCodecContext<?> next;
- if (current() == null) {
+ final var current = current();
+ final CodecContext next;
+ if (current == null) {
// Entry of first node
- next = rootNodeSchema;
+ next = rootContext;
} else {
- next = current();
+ next = current;
}
- this.schema.push(next);
- return (NodeIdentifier) current().getDomPathArgument();
+ schema.push(next);
+ return next.getDomPathArgument();
}
@SuppressWarnings({"unchecked", "rawtypes"})
private <T extends YangInstanceIdentifier.PathArgument> T enter(final Class<?> name, final Class<T> identifier) {
- final NodeCodecContext<?> next;
- if (current() == null) {
+ final var current = current();
+ final CodecContext next;
+ if (current == null) {
// Entry of first node
- next = rootNodeSchema;
+ next = rootContext;
+ } else if (current instanceof DataContainerCodecContext<?, ?, ?> currentContainer) {
+ next = currentContainer.getStreamChild((Class) name);
} else {
- Preconditions.checkArgument(current() instanceof DataContainerCodecContext, "Could not start node %s",
- name);
- next = ((DataContainerCodecContext<?,?>) current()).streamChild((Class) name);
+ throw new IllegalArgumentException("Could not start node " + name + " in non-container " + current);
}
- this.schema.push(next);
- T arg = (T) next.getDomPathArgument();
- return arg;
+ schema.push(next);
+ return identifier.cast(next.getDomPathArgument());
}
private <T extends YangInstanceIdentifier.PathArgument> T enter(final String localName, final Class<T> identifier) {
- NodeCodecContext<?> current = current();
- NodeCodecContext<?> next = ((DataObjectCodecContext<?,?>) current).getLeafChild(localName);
- this.schema.push(next);
- @SuppressWarnings("unchecked")
- T arg = (T) next.getDomPathArgument();
- return arg;
+ final var current = current();
+ final var next = ((AbstractDataObjectCodecContext<?, ?>) current).getLeafChild(localName);
+ schema.push(next);
+ return identifier.cast(next.getDomPathArgument());
}
@Override
@Override
public void endNode() throws IOException {
- NodeCodecContext<?> left = schema.pop();
- // NormalizedNode writer does not have entry into case, but into choice
- // so for leaving case, we do not emit endNode.
- if (!(left instanceof CaseNodeCodecContext)) {
+ CodecContext left = schema.pop();
+ // Due to writer does not start a new node on startCase() and on startAugmentationNode()
+ // node ending should not be triggered when associated endNode() is invoked.
+ if (!(left instanceof CaseCodecContext) && !(left instanceof AugmentationCodecContext)) {
delegate.endNode();
}
}
private Map.Entry<NodeIdentifier, Object> serializeLeaf(final String localName, final Object value) {
- Preconditions.checkArgument(current() instanceof DataObjectCodecContext);
-
- DataObjectCodecContext<?,?> currentCasted = (DataObjectCodecContext<?,?>) current();
- LeafNodeCodecContext<?> leafContext = currentCasted.getLeafChild(localName);
+ final var current = current();
+ if (!(current instanceof AbstractDataObjectCodecContext<?, ?> currentCasted)) {
+ throw new IllegalArgumentException("Unexpected current context " + current);
+ }
- NodeIdentifier domArg = (NodeIdentifier) leafContext.getDomPathArgument();
+ ValueNodeCodecContext leafContext = currentCasted.getLeafChild(localName);
+ NodeIdentifier domArg = leafContext.getDomPathArgument();
Object domValue = leafContext.getValueCodec().serialize(value);
emitSchema(leafContext.getSchema());
return new AbstractMap.SimpleEntry<>(domArg, domValue);
delegate.endNode();
}
+ @Override
+ public void anydataNode(final String name, final OpaqueObject<?> value) throws IOException {
+ final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
+ if (delegate.startAnydataNode(dom.getKey(), value.getValue().getObjectModel())) {
+ delegate.scalarValue(dom.getValue());
+ delegate.endNode();
+ }
+ }
+
@Override
public void anyxmlNode(final String name, final Object value) throws IOException {
final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
- delegate.startAnyxmlNode(dom.getKey());
- delegate.domSourceValue((DOMSource) dom.getValue());
- delegate.endNode();
+ // FIXME: this is not quite right -- we should be handling other object models, too
+ if (delegate.startAnyxmlNode(dom.getKey(), DOMSource.class)) {
+ delegate.domSourceValue((DOMSource) dom.getValue());
+ delegate.endNode();
+ }
}
@Override
public void leafSetEntryNode(final Object value) throws IOException {
- final LeafNodeCodecContext<?> ctx = (LeafNodeCodecContext<?>) current();
+ final LeafSetNodeCodecContext ctx = (LeafSetNodeCodecContext) current();
final Object domValue = ctx.getValueCodec().serialize(value);
delegate.startLeafSetEntryNode(new NodeWithValue<>(ctx.getSchema().getQName(), domValue));
delegate.scalarValue(domValue);
}
@Override
- public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType)
- throws IOException {
- delegate.startAugmentationNode(enter(augmentationType, AugmentationIdentifier.class));
+ public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType) throws IOException {
+ enter(augmentationType, NodeIdentifier.class);
}
@Override
}
@Override
- public void startMapEntryNode(final Identifier<?> key, final int childSizeHint) throws IOException {
+ public void startMapEntryNode(final Key<?> key, final int childSizeHint) throws IOException {
duplicateSchemaEnter();
- NodeIdentifierWithPredicates identifier = ((KeyedListNodeCodecContext<?>) current()).serialize(key);
+ NodeIdentifierWithPredicates identifier = ((MapCodecContext<?, ?>) current()).serialize(key);
delegate.startMapEntryNode(identifier, childSizeHint);
}
@Override
- public <T extends DataObject & Identifiable<?>> void startMapNode(final Class<T> mapEntryType,
- final int childSizeHint) throws IOException {
+ public <T extends DataObject & KeyAware<?>> void startMapNode(final Class<T> mapEntryType, final int childSizeHint)
+ throws IOException {
delegate.startMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
}
@Override
- public <T extends DataObject & Identifiable<?>> void startOrderedMapNode(final Class<T> mapEntryType,
+ public <T extends DataObject & KeyAware<?>> void startOrderedMapNode(final Class<T> mapEntryType,
final int childSizeHint) throws IOException {
delegate.startOrderedMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
}