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