Serialization/Deserialization and a host of other fixes
[controller.git] / opendaylight / md-sal / sal-protocolbuffer-encoding / src / main / java / org / opendaylight / controller / cluster / datastore / node / NormalizedNodeToProtocolBufferNode.java
1 package org.opendaylight.controller.cluster.datastore.node;
2
3 import com.google.common.base.Preconditions;
4 import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils;
5 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
6 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node;
7 import org.opendaylight.yangtools.yang.common.QName;
8 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
9 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
10 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
11 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
12 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
13 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
14 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
15 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
16 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
17 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
18 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.MixinNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
22 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
23
24 import java.util.Map;
25
26 /**
27  * NormalizedNodeToProtocolBufferNode walks the NormalizedNode tree converting it to the
28  * NormalizedMessage.Node
29  * <p/>
30  * {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode } is a tree like structure that provides a generic structure for a yang data
31  * model
32  */
33 public class NormalizedNodeToProtocolBufferNode {
34
35
36     private final Node.Builder builderRoot;
37     private NormalizedNodeMessages.Container container;
38
39     public NormalizedNodeToProtocolBufferNode() {
40
41         builderRoot = Node.newBuilder();
42     }
43
44     public void encode(String parentPath, NormalizedNode<?, ?> normalizedNode) {
45         if (parentPath == null) {
46             parentPath = "";
47         }
48
49         NormalizedNodeMessages.Container.Builder containerBuilder =
50             NormalizedNodeMessages.Container.newBuilder();
51
52         if (normalizedNode != null) {
53
54             navigateNormalizedNode(0, parentPath, normalizedNode, builderRoot);
55             // here we need to put back the Node Tree in Container
56
57             container =
58                 containerBuilder.setParentPath(parentPath).setNormalizedNode(
59                     builderRoot.build()).build();
60         } else {
61             //this can happen when an attempt was made to read from datastore and normalized node was null.
62             container = containerBuilder.setParentPath(parentPath).build();
63
64         }
65
66     }
67
68
69     private void navigateDataContainerNode(int level, final String parentPath,
70         final DataContainerNode<?> dataContainerNode,
71         Node.Builder builderParent) {
72
73         String newParentPath =
74             parentPath + "/" + dataContainerNode.getIdentifier().toString();
75         String type = getDataContainerType(dataContainerNode).getSimpleName();
76         builderParent.setPath(dataContainerNode.getIdentifier().toString())
77             .setType(type);
78
79         final Iterable<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>>
80             value =
81             dataContainerNode.getValue();
82         for (NormalizedNode<?, ?> node : value) {
83             Node.Builder builderChild = Node.newBuilder();
84             if (node instanceof MixinNode
85                 && node instanceof NormalizedNodeContainer) {
86
87                 navigateNormalizedNodeContainerMixin(level, newParentPath,
88                     (NormalizedNodeContainer<?, ?, ?>) node, builderChild);
89             } else {
90                 navigateNormalizedNode(level, newParentPath, node,
91                     builderChild);
92             }
93             builderParent.addChild(builderChild);
94         }
95     }
96
97     private Class getDataContainerType(
98         NormalizedNodeContainer<?, ?, ?> dataContainerNode) {
99         if (dataContainerNode instanceof ChoiceNode) {
100             return ChoiceNode.class;
101         } else if (dataContainerNode instanceof AugmentationNode) {
102             return AugmentationNode.class;
103         } else if (dataContainerNode instanceof ContainerNode) {
104             return ContainerNode.class;
105         } else if (dataContainerNode instanceof MapEntryNode) {
106             return MapEntryNode.class;
107         } else if (dataContainerNode instanceof UnkeyedListEntryNode) {
108             return UnkeyedListEntryNode.class;
109         } else if (dataContainerNode instanceof MapNode) {
110             return MapNode.class;
111         } else if (dataContainerNode instanceof LeafSetNode) {
112             return LeafSetNode.class;
113         }
114         throw new IllegalArgumentException(
115             "could not find the data container node type "
116                 + dataContainerNode.toString()
117         );
118     }
119
120     private void navigateNormalizedNodeContainerMixin(int level,
121         final String parentPath,
122         NormalizedNodeContainer<?, ?, ?> node, Node.Builder builderParent) {
123         String newParentPath =
124             parentPath + "/" + node.getIdentifier().toString();
125
126         builderParent.setPath(node.getIdentifier().toString()).setType(
127             this.getDataContainerType(node).getSimpleName());
128         final Iterable<? extends NormalizedNode<?, ?>> value = node.getValue();
129         for (NormalizedNode normalizedNode : value) {
130             // child node builder
131             Node.Builder builderChild = Node.newBuilder();
132             if (normalizedNode instanceof MixinNode
133                 && normalizedNode instanceof NormalizedNodeContainer) {
134                 navigateNormalizedNodeContainerMixin(level + 1, newParentPath,
135                     (NormalizedNodeContainer) normalizedNode, builderChild);
136             } else {
137                 navigateNormalizedNode(level, newParentPath, normalizedNode,
138                     builderChild);
139             }
140             builderParent.addChild(builderChild);
141
142         }
143
144
145
146     }
147
148
149     private void navigateNormalizedNode(int level,
150         String parentPath, NormalizedNode<?, ?> normalizedNode,
151         Node.Builder builderParent) {
152
153         if (normalizedNode instanceof DataContainerNode) {
154
155             final DataContainerNode<?> dataContainerNode =
156                 (DataContainerNode) normalizedNode;
157
158             navigateDataContainerNode(level + 1, parentPath, dataContainerNode,
159                 builderParent);
160         } else if (normalizedNode instanceof MixinNode
161             && normalizedNode instanceof NormalizedNodeContainer) {
162
163             navigateNormalizedNodeContainerMixin(level, parentPath,
164                 (NormalizedNodeContainer<?, ?, ?>) normalizedNode,
165                 builderParent);
166         } else {
167             if (normalizedNode instanceof LeafNode) {
168                 buildLeafNode(parentPath, normalizedNode, builderParent);
169             } else if (normalizedNode instanceof LeafSetEntryNode) {
170                 buildLeafSetEntryNode(parentPath, normalizedNode,
171                     builderParent);
172             }
173
174         }
175
176     }
177
178     private void buildLeafSetEntryNode(String parentPath,
179         NormalizedNode<?, ?> normalizedNode,
180         Node.Builder builderParent) {
181         String path =
182             parentPath + "/" + normalizedNode.getIdentifier().toString();
183         LeafSetEntryNode leafSetEntryNode = (LeafSetEntryNode) normalizedNode;
184         Map<QName, String> attributes = leafSetEntryNode.getAttributes();
185         if (!attributes.isEmpty()) {
186             NormalizedNodeMessages.Attribute.Builder builder = null;
187             for (Map.Entry<QName, String> attribute : attributes.entrySet()) {
188                 builder = NormalizedNodeMessages.Attribute.newBuilder();
189
190                 builder
191                     .setName(attribute.getKey().toString())
192                     .setValue(normalizedNode.getValue().toString());
193
194                 builderParent.addAttributes(builder.build());
195             }
196         }
197         buildNodeValue(normalizedNode, builderParent);
198     }
199
200     private void buildLeafNode(String parentPath,
201         NormalizedNode<?, ?> normalizedNode,
202         Node.Builder builderParent) {
203         Preconditions.checkNotNull(parentPath);
204         Preconditions.checkNotNull(normalizedNode);
205         String path =
206             parentPath + "/" + normalizedNode.getIdentifier().toString();
207         LeafNode leafNode = (LeafNode) normalizedNode;
208         Map<QName, String> attributes = leafNode.getAttributes();
209         if (!attributes.isEmpty()) {
210             NormalizedNodeMessages.Attribute.Builder builder = null;
211             for (Map.Entry<QName, String> attribute : attributes.entrySet()) {
212                 builder = NormalizedNodeMessages.Attribute.newBuilder();
213                 builder
214                     .setName(attribute.getKey().toString())
215                     .setValue(attribute.getValue().toString());
216
217                 builderParent.addAttributes(builder.build());
218             }
219         }
220
221         Object value = normalizedNode.getValue();
222         if (value == null) {
223             builderParent
224                 .setPath(normalizedNode.getIdentifier().toString())
225                 .setType(LeafNode.class.getSimpleName())
226                 .setValueType(String.class.getSimpleName())
227                 .setValue("");
228         } else {
229             buildNodeValue(normalizedNode, builderParent);
230         }
231     }
232
233     private void buildNodeValue(NormalizedNode<?, ?> normalizedNode,
234         Node.Builder builderParent) {
235
236         Object value = normalizedNode.getValue();
237
238         builderParent
239             .setPath(normalizedNode.getIdentifier().toString())
240             .setType(LeafNode.class.getSimpleName())
241             .setValueType((value.getClass().getSimpleName()))
242             .setValue(value.toString());
243
244         if(value.getClass().equals(YangInstanceIdentifier.class)){
245             builderParent.setInstanceIdentifierValue(
246                 InstanceIdentifierUtils
247                     .toSerializable((YangInstanceIdentifier) value));
248         }
249     }
250
251     public NormalizedNodeMessages.Container getContainer() {
252         return container;
253     }
254 }