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