2 * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import com.google.common.base.Preconditions;
14 import java.io.IOException;
15 import java.util.AbstractMap;
16 import java.util.ArrayDeque;
17 import java.util.Deque;
19 import java.util.Map.Entry;
20 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.CaseNodeCodecContext;
21 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.KeyedListNodeCodecContext;
22 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.AnyxmlNodeCodecContext;
23 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecContext;
24 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.LeafNodeCodecContext;
25 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.NodeCodecContext;
26 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.TreeNodeCodecContext;
27 import org.opendaylight.mdsal.binding.javav2.spec.base.IdentifiableItem;
28 import org.opendaylight.mdsal.binding.javav2.spec.base.Item;
29 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
30 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
31 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentation;
32 import org.opendaylight.yangtools.concepts.Delegator;
33 import org.opendaylight.yangtools.concepts.Identifiable;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
38 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
39 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
42 * Stream event writer of Binding v2 representation.
45 public final class BindingToNormalizedStreamWriter
46 implements BindingStreamEventWriter, Delegator<NormalizedNodeStreamWriter> {
48 private final Deque<NodeCodecContext<?>> schema = new ArrayDeque<>();
49 private final NormalizedNodeStreamWriter delegate;
50 private final NodeCodecContext<?> rootNodeSchema;
52 private BindingToNormalizedStreamWriter(final NodeCodecContext<?> rootNodeSchema,
53 final NormalizedNodeStreamWriter delegate) {
54 this.rootNodeSchema = requireNonNull(rootNodeSchema);
55 this.delegate = requireNonNull(delegate);
59 * Create instance of Binding v2 representation writer.
64 * - DOM writer delegator
65 * @return instance of binding writer
67 public static BindingToNormalizedStreamWriter create(final NodeCodecContext<?> schema,
68 final NormalizedNodeStreamWriter delegate) {
69 return new BindingToNormalizedStreamWriter(schema, delegate);
72 private void emitSchema(final Object schemaNode) {
73 delegate.nextDataSchemaNode((DataSchemaNode) schemaNode);
77 * Retrieves, but does not remove, the head of the queue represented by node
80 * @return head of queue
82 NodeCodecContext<?> current() {
86 private NodeIdentifier duplicateSchemaEnter() {
87 final NodeCodecContext<?> next;
88 if (current() == null) {
89 // Entry of first node
90 next = rootNodeSchema;
94 this.schema.push(next);
95 return (NodeIdentifier) current().getDomPathArgument();
98 @SuppressWarnings({ "unchecked", "rawtypes" })
99 private <T extends YangInstanceIdentifier.PathArgument> T enter(final Class<?> name, final Class<T> identifier) {
100 final NodeCodecContext<?> next;
101 if (current() == null) {
102 // Entry of first node
103 next = rootNodeSchema;
105 Preconditions.checkArgument((current() instanceof DataContainerCodecContext), "Could not start node %s",
107 next = ((DataContainerCodecContext) current()).streamChild(name);
109 this.schema.push(next);
110 return (T) next.getDomPathArgument();
113 @SuppressWarnings("rawtypes")
114 private <T extends YangInstanceIdentifier.PathArgument> T enter(final String localName, final Class<T> identifier) {
115 final NodeCodecContext<?> current = current();
116 final NodeCodecContext<?> next = ((TreeNodeCodecContext) current).getLeafChild(localName);
117 this.schema.push(next);
118 @SuppressWarnings("unchecked")
119 final T arg = (T) next.getDomPathArgument();
124 public NormalizedNodeStreamWriter getDelegate() {
129 public void endNode() throws IOException {
130 final NodeCodecContext<?> left = schema.pop();
131 // NormalizedNode writer does not have entry into case, but into choice
132 // so for leaving case, we do not emit endNode.
133 if (!(left instanceof CaseNodeCodecContext)) {
134 getDelegate().endNode();
138 private Map.Entry<NodeIdentifier, Object> serializeLeaf(final String localName, final Object value) {
139 Preconditions.checkArgument(current() instanceof TreeNodeCodecContext);
141 final TreeNodeCodecContext<?, ?> currentCasted = (TreeNodeCodecContext<?, ?>) current();
142 final LeafNodeCodecContext<?> leafContext = currentCasted.getLeafChild(localName);
144 final NodeIdentifier domArg = (NodeIdentifier) leafContext.getDomPathArgument();
145 final Object domValue = leafContext.getValueCodec().serialize(value);
146 emitSchema(leafContext.getSchema());
147 return new AbstractMap.SimpleEntry<>(domArg, domValue);
150 private Map.Entry<NodeIdentifier, Object> serializeAnyxml(final String localName, final Object value) {
151 Preconditions.checkArgument(current() instanceof TreeNodeCodecContext);
153 final TreeNodeCodecContext<?, ?> currentCasted = (TreeNodeCodecContext<?, ?>) current();
154 final AnyxmlNodeCodecContext<?> anyxmlContext = currentCasted.getAnyxmlChild(localName);
156 final NodeIdentifier domArg = (NodeIdentifier) anyxmlContext.getDomPathArgument();
157 final Object domValue = anyxmlContext.getValueCodec().serialize(value);
158 emitSchema(anyxmlContext.getSchema());
159 return new AbstractMap.SimpleEntry<>(domArg, domValue);
163 public void leafNode(final String localName, final Object value) throws IOException {
164 final Entry<NodeIdentifier, Object> dom = serializeLeaf(localName, value);
165 getDelegate().leafNode(dom.getKey(), dom.getValue());
169 public void anyxmlNode(final String name, final Object value) throws IOException {
170 final Entry<NodeIdentifier, Object> dom = serializeAnyxml(name, value);
171 getDelegate().anyxmlNode(dom.getKey(), dom.getValue());
175 public void leafSetEntryNode(final Object value) throws IOException {
176 final LeafNodeCodecContext<?> ctx = (LeafNodeCodecContext<?>) current();
177 getDelegate().leafSetEntryNode(ctx.getSchema().getQName(), ctx.getValueCodec().serialize(value));
181 public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType) throws IOException {
182 getDelegate().startAugmentationNode(enter(augmentationType, AugmentationIdentifier.class));
186 public void startCase(final Class<? extends TreeNode> caze, final int childSizeHint) {
187 enter(caze, NodeIdentifier.class);
191 public <T extends TreeNode> void startChoiceNode(final Item<T> choice, final int childSizeHint) throws IOException {
192 getDelegate().startChoiceNode(enter(choice.getType(), NodeIdentifier.class), childSizeHint);
196 public void startContainerNode(final Class<? extends TreeNode> object, final int childSizeHint)
198 getDelegate().startContainerNode(enter(object, NodeIdentifier.class), childSizeHint);
202 public void startLeafSet(final String localName, final int childSizeHint) throws IOException {
203 final NodeIdentifier id = enter(localName, NodeIdentifier.class);
204 emitSchema(current().getSchema());
205 getDelegate().startLeafSet(id, childSizeHint);
209 public void startOrderedLeafSet(final String localName, final int childSizeHint) throws IOException {
210 getDelegate().startOrderedLeafSet(enter(localName, NodeIdentifier.class), childSizeHint);
214 public <I extends TreeNode, T> void startMapEntryNode(final IdentifiableItem<I, T> keyValues,
215 final int childSizeHint) throws IOException {
216 duplicateSchemaEnter();
217 final NodeIdentifierWithPredicates identifier = ((KeyedListNodeCodecContext<?>) current()).serialize(keyValues);
218 getDelegate().startMapEntryNode(identifier, childSizeHint);
222 public <T extends TreeNode & Identifiable<?>> void startMapNode(final Class<T> mapEntryType,
223 final int childSizeHint) throws IOException {
224 getDelegate().startMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
228 public <T extends TreeNode & Identifiable<?>> void startOrderedMapNode(final Class<T> mapEntryType,
229 final int childSizeHint) throws IOException {
230 getDelegate().startOrderedMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
234 public void startUnkeyedList(final Class<? extends TreeNode> localName, final int childSizeHint)
236 getDelegate().startUnkeyedList(enter(localName, NodeIdentifier.class), childSizeHint);
240 public void startUnkeyedListItem(final int childSizeHint) throws IOException {
241 getDelegate().startUnkeyedListItem(duplicateSchemaEnter(), childSizeHint);
245 public void flush() throws IOException {
246 getDelegate().flush();
250 public void close() throws IOException {
251 getDelegate().close();
255 public void startAnydataNode(final String name, final Object value) throws IOException {
256 // TODO will be done when https://bugs.opendaylight.org/show_bug.cgi?id=8516 is completed