Merge "Make Raft messages serializable"
[controller.git] / opendaylight / md-sal / sal-protocolbuffer-encoding / src / main / java / org / opendaylight / controller / cluster / datastore / util / InstanceIdentifierUtils.java
1 package org.opendaylight.controller.cluster.datastore.util;
2
3 import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory;
4 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
5 import org.opendaylight.yangtools.yang.common.QName;
6 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
7 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16
17 /**
18  * This class contains utility methods for converting an MD-SAL
19  * YangInstanceIdentifier to and from other representations.
20  * <p>
21  * The representations convered for now are,
22  *
23  * <ul>
24  *     <li>String</li>
25  *     <li>Protocol Buffer</li>
26  * </ul>
27  */
28 public class InstanceIdentifierUtils {
29
30     protected static final Logger logger = LoggerFactory
31         .getLogger(InstanceIdentifierUtils.class);
32
33     @Deprecated
34     public static YangInstanceIdentifier from(String path) {
35         String[] ids = path.split("/");
36
37         List<YangInstanceIdentifier.PathArgument> pathArguments =
38             new ArrayList<>();
39         for (String nodeId : ids) {
40             if (!"".equals(nodeId)) {
41                 pathArguments
42                     .add(NodeIdentifierFactory.getArgument(nodeId));
43             }
44         }
45         final YangInstanceIdentifier instanceIdentifier =
46             YangInstanceIdentifier.create(pathArguments);
47         return instanceIdentifier;
48     }
49
50
51     /**
52      * Convert an MD-SAL YangInstanceIdentifier into a protocol buffer version of it
53      *
54      * @param path an MD-SAL YangInstanceIdentifier
55      * @return a protocol buffer version of the MD-SAL YangInstanceIdentifier
56      */
57     public static NormalizedNodeMessages.InstanceIdentifier toSerializable(YangInstanceIdentifier path){
58         NormalizedNodeMessages.InstanceIdentifier.Builder builder =
59             NormalizedNodeMessages.InstanceIdentifier.newBuilder();
60
61         try {
62
63             for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument pathArgument : path
64                 .getPathArguments()) {
65
66                 String nodeType = "";
67                 if(!(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier)){
68                     nodeType = pathArgument.getNodeType().toString();
69                 }
70
71                 NormalizedNodeMessages.PathArgument serializablePathArgument =
72                     NormalizedNodeMessages.PathArgument.newBuilder()
73                         .setValue(pathArgument.toString())
74                         .setType(pathArgument.getClass().getSimpleName())
75                         .setNodeType(NormalizedNodeMessages.QName.newBuilder()
76                             .setValue(nodeType))
77                         .addAllAttributes(getPathArgumentAttributes(
78                             pathArgument))
79                         .build();
80
81                 builder.addArguments(serializablePathArgument);
82             }
83
84         } catch(Exception e){
85             logger.error("An exception occurred", e);
86         }
87         return builder.build();
88     }
89
90
91     /**
92      * Convert a protocol buffer version of the MD-SAL YangInstanceIdentifier into
93      * the MD-SAL version of the YangInstanceIdentifier
94      *
95      * @param path a protocol buffer version of the MD-SAL YangInstanceIdentifier
96      * @return  an MD-SAL YangInstanceIdentifier
97      */
98     public static YangInstanceIdentifier fromSerializable(NormalizedNodeMessages.InstanceIdentifier path){
99
100         List<YangInstanceIdentifier.PathArgument> pathArguments =
101             new ArrayList<>();
102
103         for(NormalizedNodeMessages.PathArgument pathArgument : path.getArgumentsList()){
104
105             pathArguments
106                 .add(parsePathArgument(pathArgument));
107
108         }
109
110         final YangInstanceIdentifier instanceIdentifier = YangInstanceIdentifier.create(pathArguments);
111
112         return instanceIdentifier;
113     }
114
115     /**
116      * Take the various attributes of a PathArgument and package them up as
117      * protocol buffer attributes.
118      * <p>
119      *
120      * PathArguments have 4 subtypes and each of the various subtypes have
121      * different attributes
122      * <ul>
123      *     <li>
124      *         NodeIdentifier is the most basic PathArgument. It is used for
125      *         ContainerNode, LeafNode etc and has no attributes
126      *     </li>
127      *     <li>
128      *         NodeWithValue has only a single attribute. It is used for
129      *         LeafListEntryNodes and the attribute it contains is the value
130      *         of the entry
131      *     </li>
132      *     <li>
133      *         NodeIdentifierWithPredicates has a map of attributes.
134      *         It is used to represent a ListItemNode. Each entry
135      *         in the map of attributes represents the key and value of the
136      *         keys in that entry.
137      *     </li>
138      *     <li>
139      *         AugmentationIdentifier has a list of unnamed attributes. Each
140      *         attribute represents the possible children that can go within
141      *         an augmentation entry.
142      *     </li>
143      * </ul>
144      * @param pathArgument
145      * @return
146      */
147     private static Iterable<? extends NormalizedNodeMessages.Attribute> getPathArgumentAttributes(
148         YangInstanceIdentifier.PathArgument pathArgument) {
149         List<NormalizedNodeMessages.Attribute> attributes = new ArrayList<>();
150
151
152
153         if (pathArgument instanceof YangInstanceIdentifier.NodeWithValue) {
154             YangInstanceIdentifier.NodeWithValue identifier
155                 = (YangInstanceIdentifier.NodeWithValue) pathArgument;
156
157             NormalizedNodeMessages.Attribute attribute =
158                 NormalizedNodeMessages.Attribute.newBuilder()
159                     .setName("name")
160                     .setValue(identifier.getValue().toString())
161                     .setType(identifier.getValue().getClass().getSimpleName())
162                     .build();
163
164             attributes.add(attribute);
165         } else if (pathArgument instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) {
166             YangInstanceIdentifier.NodeIdentifierWithPredicates identifier
167                 = (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument;
168
169             for (QName key : identifier.getKeyValues().keySet()) {
170                 Object value = identifier.getKeyValues().get(key);
171                 NormalizedNodeMessages.Attribute attribute =
172                     NormalizedNodeMessages.Attribute.newBuilder()
173                         .setName(key.toString())
174                         .setValue(value.toString())
175                         .setType(value.getClass().getSimpleName())
176                         .build();
177
178                 attributes.add(attribute);
179
180             }
181
182         } else if(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier) {
183             YangInstanceIdentifier.AugmentationIdentifier identifier
184                 = (YangInstanceIdentifier.AugmentationIdentifier) pathArgument;
185
186             for (QName key : identifier.getPossibleChildNames()) {
187                 Object value = key;
188                 NormalizedNodeMessages.Attribute attribute =
189                     NormalizedNodeMessages.Attribute.newBuilder()
190                         .setName(key.toString())
191                         .setValue(value.toString())
192                         .setType(value.getClass().getSimpleName())
193                         .build();
194
195                 attributes.add(attribute);
196
197             }
198         }
199
200         return attributes;
201     }
202
203
204     /**
205      * Parse a protocol buffer PathArgument and return an MD-SAL PathArgument
206      *
207      * @param pathArgument protocol buffer PathArgument
208      * @return MD-SAL PathArgument
209      */
210     private static YangInstanceIdentifier.PathArgument parsePathArgument(NormalizedNodeMessages.PathArgument pathArgument) {
211         if (YangInstanceIdentifier.NodeWithValue.class.getSimpleName().equals(pathArgument.getType())) {
212
213             YangInstanceIdentifier.NodeWithValue nodeWithValue =
214                 new YangInstanceIdentifier.NodeWithValue(
215                     QName.create(pathArgument.getNodeType().getValue()),
216                     parseAttribute(pathArgument.getAttributes(0)));
217
218             return nodeWithValue;
219
220         } else if(YangInstanceIdentifier.NodeIdentifierWithPredicates.class.getSimpleName().equals(pathArgument.getType())){
221
222             YangInstanceIdentifier.NodeIdentifierWithPredicates
223                 nodeIdentifierWithPredicates =
224                 new YangInstanceIdentifier.NodeIdentifierWithPredicates(
225                     QName.create(pathArgument.getNodeType().getValue()), toAttributesMap(pathArgument.getAttributesList()));
226
227             return nodeIdentifierWithPredicates;
228
229         } else if(YangInstanceIdentifier.AugmentationIdentifier.class.getSimpleName().equals(pathArgument.getType())){
230
231             Set<QName> qNameSet = new HashSet<>();
232
233             for(NormalizedNodeMessages.Attribute attribute : pathArgument.getAttributesList()){
234                 qNameSet.add(QName.create(attribute.getValue()));
235             }
236
237             return new YangInstanceIdentifier.AugmentationIdentifier(qNameSet);
238         }
239
240         return NodeIdentifierFactory.getArgument(pathArgument.getValue());
241     }
242
243     private static Map<QName, Object> toAttributesMap(
244         List<NormalizedNodeMessages.Attribute> attributesList) {
245
246         Map<QName, Object> map = new HashMap<>();
247
248         for(NormalizedNodeMessages.Attribute attribute : attributesList){
249             String name = attribute.getName();
250             Object value = parseAttribute(attribute);
251
252             map.put(QName.create(name), value);
253         }
254
255         return map;
256     }
257
258     /**
259      * FIXME: This method only covers a subset of values that may go in an InstanceIdentifier
260      *
261      * @param attribute
262      * @return
263      */
264     private static Object parseAttribute(NormalizedNodeMessages.Attribute attribute){
265         if(Short.class.getSimpleName().equals(attribute.getType())) {
266             return Short.parseShort(attribute.getValue());
267         } else if(Long.class.getSimpleName().equals(attribute.getType())){
268             return Long.parseLong(attribute.getValue());
269         } else if(Boolean.class.getSimpleName().equals(attribute.getType())){
270             return Boolean.parseBoolean(attribute.getValue());
271         } else if(Integer.class.getSimpleName().equals(attribute.getType())){
272             return Integer.parseInt(attribute.getValue());
273         }
274
275         return attribute.getValue();
276     }
277 }