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