2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.binding.dom.codec.impl;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import java.io.IOException;
14 import java.util.AbstractMap;
15 import java.util.ArrayDeque;
16 import java.util.Deque;
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;
36 final class BindingToNormalizedStreamWriter implements AnydataBindingStreamWriter,
37 Delegator<NormalizedNodeStreamWriter> {
38 private final Deque<NodeCodecContext> schema = new ArrayDeque<>();
39 private final NormalizedNodeStreamWriter delegate;
40 private final NodeCodecContext rootNodeSchema;
42 BindingToNormalizedStreamWriter(final NodeCodecContext rootNodeSchema, final NormalizedNodeStreamWriter delegate) {
43 this.rootNodeSchema = requireNonNull(rootNodeSchema);
44 this.delegate = requireNonNull(delegate);
47 static @NonNull BindingToNormalizedStreamWriter create(final NodeCodecContext schema,
48 final NormalizedNodeStreamWriter delegate) {
49 return new BindingToNormalizedStreamWriter(schema, delegate);
52 private void emitSchema(final Object schemaNode) {
53 delegate.nextDataSchemaNode((DataSchemaNode) schemaNode);
56 NodeCodecContext current() {
60 private NodeIdentifier duplicateSchemaEnter() {
61 final NodeCodecContext next;
62 if (current() == null) {
63 // Entry of first node
64 next = rootNodeSchema;
68 this.schema.push(next);
69 return (NodeIdentifier) current().getDomPathArgument();
72 @SuppressWarnings({"unchecked", "rawtypes"})
73 private <T extends YangInstanceIdentifier.PathArgument> T enter(final Class<?> name, final Class<T> identifier) {
74 final NodeCodecContext next;
75 if (current() == null) {
76 // Entry of first node
77 next = rootNodeSchema;
79 checkArgument(current() instanceof DataContainerCodecContext, "Could not start node %s", name);
80 next = ((DataContainerCodecContext<?,?>) current()).streamChild((Class) name);
82 this.schema.push(next);
83 T arg = (T) next.getDomPathArgument();
87 private <T extends YangInstanceIdentifier.PathArgument> T enter(final String localName, final Class<T> identifier) {
88 NodeCodecContext current = current();
89 NodeCodecContext next = ((DataObjectCodecContext<?, ?>) current).getLeafChild(localName);
90 this.schema.push(next);
91 @SuppressWarnings("unchecked")
92 T arg = (T) next.getDomPathArgument();
97 public NormalizedNodeStreamWriter getDelegate() {
102 public void endNode() throws IOException {
103 NodeCodecContext left = schema.pop();
104 // NormalizedNode writer does not have entry into case, but into choice
105 // so for leaving case, we do not emit endNode.
106 if (!(left instanceof CaseNodeCodecContext)) {
111 private Map.Entry<NodeIdentifier, Object> serializeLeaf(final String localName, final Object value) {
112 checkArgument(current() instanceof DataObjectCodecContext);
114 DataObjectCodecContext<?,?> currentCasted = (DataObjectCodecContext<?,?>) current();
115 ValueNodeCodecContext leafContext = currentCasted.getLeafChild(localName);
117 NodeIdentifier domArg = leafContext.getDomPathArgument();
118 Object domValue = leafContext.getValueCodec().serialize(value);
119 emitSchema(leafContext.getSchema());
120 return new AbstractMap.SimpleEntry<>(domArg, domValue);
124 public void leafNode(final String localName, final Object value) throws IOException {
125 final Entry<NodeIdentifier, Object> dom = serializeLeaf(localName, value);
126 delegate.startLeafNode(dom.getKey());
127 delegate.scalarValue(dom.getValue());
132 public void anydataNode(final String name, final OpaqueObject<?> value) throws IOException {
133 final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
134 if (delegate.startAnydataNode(dom.getKey(), value.getValue().getObjectModel())) {
135 delegate.scalarValue(dom.getValue());
141 public void anyxmlNode(final String name, final Object value) throws IOException {
142 final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
143 // FIXME: this is not quite right -- we should be handling other object models, too
144 if (delegate.startAnyxmlNode(dom.getKey(), DOMSource.class)) {
145 delegate.domSourceValue((DOMSource) dom.getValue());
151 public void leafSetEntryNode(final Object value) throws IOException {
152 final LeafSetNodeCodecContext ctx = (LeafSetNodeCodecContext) current();
153 final Object domValue = ctx.getValueCodec().serialize(value);
154 delegate.startLeafSetEntryNode(new NodeWithValue<>(ctx.getSchema().getQName(), domValue));
155 delegate.scalarValue(domValue);
160 public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType)
162 delegate.startAugmentationNode(enter(augmentationType, AugmentationIdentifier.class));
166 public void startCase(final Class<? extends DataObject> caze, final int childSizeHint) {
167 enter(caze, NodeIdentifier.class);
171 public void startChoiceNode(final Class<? extends DataContainer> type, final int childSizeHint)
173 delegate.startChoiceNode(enter(type, NodeIdentifier.class), childSizeHint);
177 public void startContainerNode(final Class<? extends DataObject> object, final int childSizeHint)
179 delegate.startContainerNode(enter(object, NodeIdentifier.class), childSizeHint);
183 public void startLeafSet(final String localName, final int childSizeHint) throws IOException {
184 final NodeIdentifier id = enter(localName, NodeIdentifier.class);
185 emitSchema(current().getSchema());
186 delegate.startLeafSet(id, childSizeHint);
190 public void startOrderedLeafSet(final String localName, final int childSizeHint) throws IOException {
191 delegate.startOrderedLeafSet(enter(localName, NodeIdentifier.class), childSizeHint);
195 public void startMapEntryNode(final Identifier<?> key, final int childSizeHint) throws IOException {
196 duplicateSchemaEnter();
197 NodeIdentifierWithPredicates identifier = ((KeyedListNodeCodecContext<?, ?>) current()).serialize(key);
198 delegate.startMapEntryNode(identifier, childSizeHint);
202 public <T extends DataObject & Identifiable<?>> void startMapNode(final Class<T> mapEntryType,
203 final int childSizeHint) throws IOException {
204 delegate.startMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
208 public <T extends DataObject & Identifiable<?>> void startOrderedMapNode(final Class<T> mapEntryType,
209 final int childSizeHint) throws IOException {
210 delegate.startOrderedMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
214 public void startUnkeyedList(final Class<? extends DataObject> obj, final int childSizeHint) throws IOException {
215 delegate.startUnkeyedList(enter(obj, NodeIdentifier.class), childSizeHint);
219 public void startUnkeyedListItem(final int childSizeHint) throws IOException {
220 delegate.startUnkeyedListItem(duplicateSchemaEnter(), childSizeHint);
224 public void flush() throws IOException {
229 public void close() throws IOException {