Fix license header violations in sal-clustering-commons
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / main / java / org / opendaylight / controller / cluster / datastore / util / InstanceIdentifierUtils.java
1 /*
2  * Copyright (c) 2014, 2015 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
9 package org.opendaylight.controller.cluster.datastore.util;
10
11 import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory;
12 import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory;
13 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.PathArgumentSerializer;
14 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameDeSerializationContext;
15 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameDeSerializationContextImpl;
16 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameSerializationContext;
17 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameSerializationContextImpl;
18 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
19 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30
31 /**
32  * This class contains utility methods for converting an MD-SAL
33  * YangInstanceIdentifier to and from other representations.
34  * <p>
35  * The representations convered for now are,
36  *
37  * <ul>
38  *     <li>String</li>
39  *     <li>Protocol Buffer</li>
40  * </ul>
41  */
42 public class InstanceIdentifierUtils {
43
44     protected static final Logger logger = LoggerFactory
45         .getLogger(InstanceIdentifierUtils.class);
46
47     /**
48      * Convert an MD-SAL YangInstanceIdentifier into a protocol buffer version of it
49      *
50      * @param path an MD-SAL YangInstanceIdentifier
51      * @return a protocol buffer version of the MD-SAL YangInstanceIdentifier
52      */
53     public static NormalizedNodeMessages.InstanceIdentifier toSerializable(YangInstanceIdentifier path) {
54         QNameSerializationContextImpl context = new QNameSerializationContextImpl();
55         Builder builder = toSerializableBuilder(path, context);
56         return builder.addAllCode(context.getCodes()).build();
57     }
58
59     public static NormalizedNodeMessages.InstanceIdentifier toSerializable(
60             YangInstanceIdentifier path, QNameSerializationContext context) {
61         return toSerializableBuilder(path, context).build();
62     }
63
64     private static NormalizedNodeMessages.InstanceIdentifier.Builder toSerializableBuilder(
65             YangInstanceIdentifier path, QNameSerializationContext context) {
66         NormalizedNodeMessages.InstanceIdentifier.Builder builder =
67             NormalizedNodeMessages.InstanceIdentifier.newBuilder();
68
69         try {
70             for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.
71                                             PathArgument pathArgument : path.getPathArguments()) {
72                 NormalizedNodeMessages.PathArgument serializablePathArgument;
73                 if(context == null) {
74                     String nodeType = "";
75                     if(!(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier)){
76                         nodeType = pathArgument.getNodeType().toString();
77                     }
78
79                     serializablePathArgument = NormalizedNodeMessages.PathArgument.newBuilder()
80                             .setValue(pathArgument.toString())
81                             .setType(pathArgument.getClass().getSimpleName())
82                             .setNodeType(NormalizedNodeMessages.QName.newBuilder().setValue(nodeType))
83                             .addAllAttributes(getPathArgumentAttributes(pathArgument)).build();
84                 } else {
85                     serializablePathArgument = PathArgumentSerializer.serialize(context, pathArgument);
86                 }
87
88                 builder.addArguments(serializablePathArgument);
89             }
90         } catch(Exception e){
91             logger.error("An exception occurred", e);
92         }
93
94         return builder;
95     }
96
97
98     /**
99      * Convert a protocol buffer version of the MD-SAL YangInstanceIdentifier into
100      * the MD-SAL version of the YangInstanceIdentifier
101      *
102      * @param path a protocol buffer version of the MD-SAL YangInstanceIdentifier
103      * @return  an MD-SAL YangInstanceIdentifier
104      */
105     public static YangInstanceIdentifier fromSerializable(NormalizedNodeMessages.InstanceIdentifier path) {
106         return fromSerializable(path, new QNameDeSerializationContextImpl(path.getCodeList()));
107     }
108
109     public static YangInstanceIdentifier fromSerializable(NormalizedNodeMessages.InstanceIdentifier path,
110             QNameDeSerializationContext context) {
111
112         List<YangInstanceIdentifier.PathArgument> pathArguments = new ArrayList<>();
113
114         for(NormalizedNodeMessages.PathArgument pathArgument : path.getArgumentsList()) {
115             if(context == null || pathArgument.hasType()) {
116                 pathArguments.add(parsePathArgument(pathArgument));
117             } else {
118                 pathArguments.add(PathArgumentSerializer.deSerialize(context, pathArgument));
119             }
120         }
121
122         return YangInstanceIdentifier.create(pathArguments);
123     }
124
125     /**
126      * Take the various attributes of a PathArgument and package them up as
127      * protocol buffer attributes.
128      * <p>
129      *
130      * PathArguments have 4 subtypes and each of the various subtypes have
131      * different attributes
132      * <ul>
133      *     <li>
134      *         NodeIdentifier is the most basic PathArgument. It is used for
135      *         ContainerNode, LeafNode etc and has no attributes
136      *     </li>
137      *     <li>
138      *         NodeWithValue has only a single attribute. It is used for
139      *         LeafListEntryNodes and the attribute it contains is the value
140      *         of the entry
141      *     </li>
142      *     <li>
143      *         NodeIdentifierWithPredicates has a map of attributes.
144      *         It is used to represent a ListItemNode. Each entry
145      *         in the map of attributes represents the key and value of the
146      *         keys in that entry.
147      *     </li>
148      *     <li>
149      *         AugmentationIdentifier has a list of unnamed attributes. Each
150      *         attribute represents the possible children that can go within
151      *         an augmentation entry.
152      *     </li>
153      * </ul>
154      * @param pathArgument
155      * @return
156      */
157     private static Iterable<? extends NormalizedNodeMessages.Attribute> getPathArgumentAttributes(
158         YangInstanceIdentifier.PathArgument pathArgument) {
159         List<NormalizedNodeMessages.Attribute> attributes = new ArrayList<>();
160
161
162
163         if (pathArgument instanceof YangInstanceIdentifier.NodeWithValue) {
164             YangInstanceIdentifier.NodeWithValue identifier
165                 = (YangInstanceIdentifier.NodeWithValue) pathArgument;
166
167             NormalizedNodeMessages.Attribute attribute =
168                 NormalizedNodeMessages.Attribute.newBuilder()
169                     .setName("name")
170                     .setValue(identifier.getValue().toString())
171                     .setType(identifier.getValue().getClass().getSimpleName())
172                     .build();
173
174             attributes.add(attribute);
175         } else if (pathArgument instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) {
176             YangInstanceIdentifier.NodeIdentifierWithPredicates identifier
177                 = (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument;
178
179             for (QName key : identifier.getKeyValues().keySet()) {
180                 Object value = identifier.getKeyValues().get(key);
181                 NormalizedNodeMessages.Attribute attribute =
182                     NormalizedNodeMessages.Attribute.newBuilder()
183                         .setName(key.toString())
184                         .setValue(value.toString())
185                         .setType(value.getClass().getSimpleName())
186                         .build();
187
188                 attributes.add(attribute);
189
190             }
191
192         } else if(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier) {
193             YangInstanceIdentifier.AugmentationIdentifier identifier
194                 = (YangInstanceIdentifier.AugmentationIdentifier) pathArgument;
195
196             for (QName key : identifier.getPossibleChildNames()) {
197                 Object value = key;
198                 NormalizedNodeMessages.Attribute attribute =
199                     NormalizedNodeMessages.Attribute.newBuilder()
200                         .setName(key.toString())
201                         .setValue(value.toString())
202                         .setType(value.getClass().getSimpleName())
203                         .build();
204
205                 attributes.add(attribute);
206
207             }
208         }
209
210         return attributes;
211     }
212
213
214     /**
215      * Parse a protocol buffer PathArgument and return an MD-SAL PathArgument
216      *
217      * @param pathArgument protocol buffer PathArgument
218      * @return MD-SAL PathArgument
219      */
220     private static YangInstanceIdentifier.PathArgument parsePathArgument(
221             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 }