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