Merge "Bug 2086: Adding normalized node stream reader and writer."
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / test / java / org / opendaylight / controller / cluster / datastore / node / utils / stream / NormalizedNodeWriter.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.controller.cluster.datastore.node.utils.stream;
9
10 import com.google.common.base.Preconditions;
11 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
12 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
13 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
14 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
15 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
16 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
17 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
18 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
24
25 import java.io.Closeable;
26 import java.io.Flushable;
27 import java.io.IOException;
28 import java.util.Collection;
29
30 import static org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
31
32
33 /**
34  * This class is used only for testing purpose for now, we may use similar logic while integrating
35  * with cluster
36  */
37
38 public class NormalizedNodeWriter implements Closeable, Flushable {
39     private final NormalizedNodeStreamWriter writer;
40
41     private NormalizedNodeWriter(final NormalizedNodeStreamWriter writer) {
42         this.writer = Preconditions.checkNotNull(writer);
43     }
44
45     protected final NormalizedNodeStreamWriter getWriter() {
46         return writer;
47     }
48
49     /**
50      * Create a new writer backed by a {@link org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter}.
51      *
52      * @param writer Back-end writer
53      * @return A new instance.
54      */
55     public static NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer) {
56         return new NormalizedNodeWriter(writer);
57     }
58
59
60     /**
61      * Iterate over the provided {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode} and emit write
62      * events to the encapsulated {@link org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter}.
63      *
64      * @param node Node
65      * @return
66      * @throws java.io.IOException when thrown from the backing writer.
67      */
68     public final NormalizedNodeWriter write(final NormalizedNode<?, ?> node) throws IOException {
69         if (wasProcessedAsComplexNode(node)) {
70             return this;
71         }
72
73         if (wasProcessAsSimpleNode(node)) {
74             return this;
75         }
76
77         throw new IllegalStateException("It wasn't possible to serialize node " + node);
78     }
79
80     @Override
81     public void flush() throws IOException {
82         writer.flush();
83     }
84
85     @Override
86     public void close() throws IOException {
87         writer.flush();
88         writer.close();
89     }
90
91     /**
92      * Emit a best guess of a hint for a particular set of children. It evaluates the
93      * iterable to see if the size can be easily gotten to. If it is, we hint at the
94      * real number of child nodes. Otherwise we emit UNKNOWN_SIZE.
95      *
96      * @param children Child nodes
97      * @return Best estimate of the collection size required to hold all the children.
98      */
99     static final int childSizeHint(final Iterable<?> children) {
100         return (children instanceof Collection) ? ((Collection<?>) children).size() : UNKNOWN_SIZE;
101     }
102
103     private boolean wasProcessAsSimpleNode(final NormalizedNode<?, ?> node) throws IOException {
104         if (node instanceof LeafSetEntryNode) {
105             final LeafSetEntryNode<?> nodeAsLeafList = (LeafSetEntryNode<?>)node;
106             writer.leafSetEntryNode(nodeAsLeafList.getIdentifier(), nodeAsLeafList.getValue());
107             return true;
108         } else if (node instanceof LeafNode) {
109             final LeafNode<?> nodeAsLeaf = (LeafNode<?>)node;
110             writer.leafNode(nodeAsLeaf.getIdentifier(), nodeAsLeaf.getValue());
111             return true;
112         } else if (node instanceof AnyXmlNode) {
113             final AnyXmlNode anyXmlNode = (AnyXmlNode)node;
114             writer.anyxmlNode(anyXmlNode.getIdentifier(), anyXmlNode.getValue());
115             return true;
116         }
117
118         return false;
119     }
120
121     /**
122      * Emit events for all children and then emit an endNode() event.
123      *
124      * @param children Child iterable
125      * @return True
126      * @throws java.io.IOException when the writer reports it
127      */
128     protected final boolean writeChildren(final Iterable<? extends NormalizedNode<?, ?>> children) throws IOException {
129         for (NormalizedNode<?, ?> child : children) {
130             write(child);
131         }
132
133         writer.endNode();
134         return true;
135     }
136
137     protected boolean writeMapEntryNode(final MapEntryNode node) throws IOException {
138         writer.startMapEntryNode(node.getIdentifier(), childSizeHint(node.getValue()));
139         return writeChildren(node.getValue());
140     }
141
142     private boolean wasProcessedAsComplexNode(final NormalizedNode<?, ?> node) throws IOException {
143         if (node instanceof ContainerNode) {
144             final ContainerNode n = (ContainerNode) node;
145             writer.startContainerNode(n.getIdentifier(), childSizeHint(n.getValue()));
146             return writeChildren(n.getValue());
147         }
148         if (node instanceof MapEntryNode) {
149             return writeMapEntryNode((MapEntryNode) node);
150         }
151         if (node instanceof UnkeyedListEntryNode) {
152             final UnkeyedListEntryNode n = (UnkeyedListEntryNode) node;
153             writer.startUnkeyedListItem(n.getIdentifier(), childSizeHint(n.getValue()));
154             return writeChildren(n.getValue());
155         }
156         if (node instanceof ChoiceNode) {
157             final ChoiceNode n = (ChoiceNode) node;
158             writer.startChoiceNode(n.getIdentifier(), childSizeHint(n.getValue()));
159             return writeChildren(n.getValue());
160         }
161         if (node instanceof AugmentationNode) {
162             final AugmentationNode n = (AugmentationNode) node;
163             writer.startAugmentationNode(n.getIdentifier());
164             return writeChildren(n.getValue());
165         }
166         if (node instanceof UnkeyedListNode) {
167             final UnkeyedListNode n = (UnkeyedListNode) node;
168             writer.startUnkeyedList(n.getIdentifier(), childSizeHint(n.getValue()));
169             return writeChildren(n.getValue());
170         }
171         if (node instanceof OrderedMapNode) {
172             final OrderedMapNode n = (OrderedMapNode) node;
173             writer.startOrderedMapNode(n.getIdentifier(), childSizeHint(n.getValue()));
174             return writeChildren(n.getValue());
175         }
176         if (node instanceof MapNode) {
177             final MapNode n = (MapNode) node;
178             writer.startMapNode(n.getIdentifier(), childSizeHint(n.getValue()));
179             return writeChildren(n.getValue());
180         }
181         if (node instanceof LeafSetNode) {
182             //covers also OrderedLeafSetNode for which doesn't exist start* method
183             final LeafSetNode<?> n = (LeafSetNode<?>) node;
184             writer.startLeafSet(n.getIdentifier(), childSizeHint(n.getValue()));
185             return writeChildren(n.getValue());
186         }
187
188         return false;
189     }
190 }