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