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