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