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