Adjust for AnydataExtension being integrated
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / BindingToNormalizedStreamWriter.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.mdsal.binding.dom.codec.impl;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
12
13 import java.io.IOException;
14 import java.util.AbstractMap;
15 import java.util.ArrayDeque;
16 import java.util.Deque;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import javax.xml.transform.dom.DOMSource;
20 import org.opendaylight.yangtools.concepts.Delegator;
21 import org.opendaylight.yangtools.yang.binding.Augmentation;
22 import org.opendaylight.yangtools.yang.binding.DataContainer;
23 import org.opendaylight.yangtools.yang.binding.DataObject;
24 import org.opendaylight.yangtools.yang.binding.Identifiable;
25 import org.opendaylight.yangtools.yang.binding.Identifier;
26 import org.opendaylight.yangtools.yang.binding.OpaqueObject;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
32 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
33 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
34
35 final class BindingToNormalizedStreamWriter implements AnydataBindingStreamWriter,
36         Delegator<NormalizedNodeStreamWriter> {
37     private final Deque<NodeCodecContext> schema = new ArrayDeque<>();
38     private final NormalizedNodeStreamWriter delegate;
39     private final NodeCodecContext rootNodeSchema;
40
41     BindingToNormalizedStreamWriter(final NodeCodecContext rootNodeSchema, final NormalizedNodeStreamWriter delegate) {
42         this.rootNodeSchema = requireNonNull(rootNodeSchema);
43         this.delegate = requireNonNull(delegate);
44     }
45
46     static BindingToNormalizedStreamWriter create(final NodeCodecContext schema,
47             final NormalizedNodeStreamWriter delegate) {
48         return new BindingToNormalizedStreamWriter(schema, delegate);
49     }
50
51     private void emitSchema(final Object schemaNode) {
52         delegate.nextDataSchemaNode((DataSchemaNode) schemaNode);
53     }
54
55     NodeCodecContext current() {
56         return schema.peek();
57     }
58
59     private NodeIdentifier duplicateSchemaEnter() {
60         final NodeCodecContext next;
61         if (current() == null) {
62             // Entry of first node
63             next = rootNodeSchema;
64         } else {
65             next = current();
66         }
67         this.schema.push(next);
68         return (NodeIdentifier) current().getDomPathArgument();
69     }
70
71     @SuppressWarnings({"unchecked", "rawtypes"})
72     private <T extends YangInstanceIdentifier.PathArgument> T enter(final Class<?> name, final Class<T> identifier) {
73         final NodeCodecContext next;
74         if (current() == null) {
75             // Entry of first node
76             next = rootNodeSchema;
77         } else {
78             checkArgument(current() instanceof DataContainerCodecContext, "Could not start node %s", name);
79             next = ((DataContainerCodecContext<?,?>) current()).streamChild((Class) name);
80         }
81         this.schema.push(next);
82         T arg = (T) next.getDomPathArgument();
83         return arg;
84     }
85
86     private <T extends YangInstanceIdentifier.PathArgument> T enter(final String localName, final Class<T> identifier) {
87         NodeCodecContext current = current();
88         NodeCodecContext next = ((DataObjectCodecContext<?, ?>) current).getLeafChild(localName);
89         this.schema.push(next);
90         @SuppressWarnings("unchecked")
91         T arg = (T) next.getDomPathArgument();
92         return arg;
93     }
94
95     @Override
96     public NormalizedNodeStreamWriter getDelegate() {
97         return delegate;
98     }
99
100     @Override
101     public void endNode() throws IOException {
102         NodeCodecContext left = schema.pop();
103         // NormalizedNode writer does not have entry into case, but into choice
104         // so for leaving case, we do not emit endNode.
105         if (!(left instanceof CaseNodeCodecContext)) {
106             delegate.endNode();
107         }
108     }
109
110     private Map.Entry<NodeIdentifier, Object> serializeLeaf(final String localName, final Object value) {
111         checkArgument(current() instanceof DataObjectCodecContext);
112
113         DataObjectCodecContext<?,?> currentCasted = (DataObjectCodecContext<?,?>) current();
114         ValueNodeCodecContext leafContext = currentCasted.getLeafChild(localName);
115
116         NodeIdentifier domArg = leafContext.getDomPathArgument();
117         Object domValue = leafContext.getValueCodec().serialize(value);
118         emitSchema(leafContext.getSchema());
119         return new AbstractMap.SimpleEntry<>(domArg, domValue);
120     }
121
122     @Override
123     public void leafNode(final String localName, final Object value) throws IOException {
124         final Entry<NodeIdentifier, Object> dom = serializeLeaf(localName, value);
125         delegate.startLeafNode(dom.getKey());
126         delegate.scalarValue(dom.getValue());
127         delegate.endNode();
128     }
129
130     @Override
131     public void anydataNode(final String name, final OpaqueObject<?> value) throws IOException {
132         final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
133         if (delegate.startAnydataNode(dom.getKey(), value.getValue().getObjectModel())) {
134             delegate.scalarValue(dom.getValue());
135             delegate.endNode();
136         }
137     }
138
139     @Override
140     public void anyxmlNode(final String name, final Object value) throws IOException {
141         final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
142         delegate.startAnyxmlNode(dom.getKey());
143         delegate.domSourceValue((DOMSource) dom.getValue());
144         delegate.endNode();
145     }
146
147     @Override
148     public void leafSetEntryNode(final Object value) throws IOException {
149         final LeafSetNodeCodecContext ctx = (LeafSetNodeCodecContext) current();
150         final Object domValue = ctx.getValueCodec().serialize(value);
151         delegate.startLeafSetEntryNode(new NodeWithValue<>(ctx.getSchema().getQName(), domValue));
152         delegate.scalarValue(domValue);
153         delegate.endNode();
154     }
155
156     @Override
157     public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType)
158             throws IOException {
159         delegate.startAugmentationNode(enter(augmentationType, AugmentationIdentifier.class));
160     }
161
162     @Override
163     public void startCase(final Class<? extends DataObject> caze, final int childSizeHint) {
164         enter(caze, NodeIdentifier.class);
165     }
166
167     @Override
168     public void startChoiceNode(final Class<? extends DataContainer> type, final int childSizeHint)
169             throws IOException {
170         delegate.startChoiceNode(enter(type, NodeIdentifier.class), childSizeHint);
171     }
172
173     @Override
174     public void startContainerNode(final Class<? extends DataObject> object, final int childSizeHint)
175             throws IOException {
176         delegate.startContainerNode(enter(object, NodeIdentifier.class), childSizeHint);
177     }
178
179     @Override
180     public void startLeafSet(final String localName, final int childSizeHint) throws IOException {
181         final NodeIdentifier id = enter(localName, NodeIdentifier.class);
182         emitSchema(current().getSchema());
183         delegate.startLeafSet(id, childSizeHint);
184     }
185
186     @Override
187     public void startOrderedLeafSet(final String localName, final int childSizeHint) throws IOException {
188         delegate.startOrderedLeafSet(enter(localName, NodeIdentifier.class), childSizeHint);
189     }
190
191     @Override
192     public void startMapEntryNode(final Identifier<?> key, final int childSizeHint) throws IOException {
193         duplicateSchemaEnter();
194         NodeIdentifierWithPredicates identifier = ((KeyedListNodeCodecContext<?>) current()).serialize(key);
195         delegate.startMapEntryNode(identifier, childSizeHint);
196     }
197
198     @Override
199     public <T extends DataObject & Identifiable<?>> void startMapNode(final Class<T> mapEntryType,
200             final int childSizeHint) throws IOException {
201         delegate.startMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
202     }
203
204     @Override
205     public <T extends DataObject & Identifiable<?>> void startOrderedMapNode(final Class<T> mapEntryType,
206             final int childSizeHint) throws IOException {
207         delegate.startOrderedMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
208     }
209
210     @Override
211     public void startUnkeyedList(final Class<? extends DataObject> obj, final int childSizeHint) throws IOException {
212         delegate.startUnkeyedList(enter(obj, NodeIdentifier.class), childSizeHint);
213     }
214
215     @Override
216     public void startUnkeyedListItem(final int childSizeHint) throws IOException {
217         delegate.startUnkeyedListItem(duplicateSchemaEnter(), childSizeHint);
218     }
219
220     @Override
221     public void flush() throws IOException {
222         delegate.flush();
223     }
224
225     @Override
226     public void close() throws IOException {
227         delegate.close();
228     }
229 }