312eeef6d5bf7c53ebf2a1c09886ba6690a37512
[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 java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory;
18 import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory;
19 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.PathArgumentSerializer;
20 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameDeSerializationContext;
21 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameDeSerializationContextImpl;
22 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameSerializationContext;
23 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameSerializationContextImpl;
24 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
25 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
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     private static final Logger LOG = LoggerFactory.getLogger(InstanceIdentifierUtils.class);
48
49     /**
50      * Convert an MD-SAL YangInstanceIdentifier into a protocol buffer version of it.
51      *
52      * @param path an MD-SAL YangInstanceIdentifier
53      * @return a protocol buffer version of the MD-SAL YangInstanceIdentifier
54      */
55     public static NormalizedNodeMessages.InstanceIdentifier toSerializable(YangInstanceIdentifier path) {
56         QNameSerializationContextImpl context = new QNameSerializationContextImpl();
57         Builder builder = toSerializableBuilder(path, context);
58         return builder.addAllCode(context.getCodes()).build();
59     }
60
61     public static NormalizedNodeMessages.InstanceIdentifier toSerializable(
62             YangInstanceIdentifier path, QNameSerializationContext context) {
63         return toSerializableBuilder(path, context).build();
64     }
65
66     @SuppressWarnings("checkstyle:IllegalCatch")
67     private static NormalizedNodeMessages.InstanceIdentifier.Builder toSerializableBuilder(
68             YangInstanceIdentifier path, QNameSerializationContext context) {
69         NormalizedNodeMessages.InstanceIdentifier.Builder builder =
70             NormalizedNodeMessages.InstanceIdentifier.newBuilder();
71
72         try {
73             for (PathArgument pathArgument : path.getPathArguments()) {
74                 NormalizedNodeMessages.PathArgument serializablePathArgument;
75                 if (context == null) {
76                     String nodeType = "";
77                     if (!(pathArgument instanceof AugmentationIdentifier)) {
78                         nodeType = pathArgument.getNodeType().toString();
79                     }
80
81                     serializablePathArgument = NormalizedNodeMessages.PathArgument.newBuilder()
82                             .setValue(pathArgument.toString())
83                             .setType(pathArgument.getClass().getSimpleName())
84                             .setNodeType(NormalizedNodeMessages.QName.newBuilder().setValue(nodeType))
85                             .addAllAttributes(getPathArgumentAttributes(pathArgument)).build();
86                 } else {
87                     serializablePathArgument = PathArgumentSerializer.serialize(context, pathArgument);
88                 }
89
90                 builder.addArguments(serializablePathArgument);
91             }
92         } catch (Exception e) {
93             LOG.error("An exception occurred", e);
94         }
95
96         return builder;
97     }
98
99
100     /**
101      * Convert a protocol buffer version of the MD-SAL YangInstanceIdentifier into
102      * the MD-SAL version of the YangInstanceIdentifier.
103      *
104      * @param path a protocol buffer version of the MD-SAL YangInstanceIdentifier
105      * @return  an MD-SAL YangInstanceIdentifier
106      */
107     public static YangInstanceIdentifier fromSerializable(NormalizedNodeMessages.InstanceIdentifier path) {
108         return fromSerializable(path, new QNameDeSerializationContextImpl(path.getCodeList()));
109     }
110
111     public static YangInstanceIdentifier fromSerializable(NormalizedNodeMessages.InstanceIdentifier path,
112             QNameDeSerializationContext context) {
113
114         List<PathArgument> pathArguments = new ArrayList<>();
115
116         for (NormalizedNodeMessages.PathArgument pathArgument : path.getArgumentsList()) {
117             if (context == null || pathArgument.hasType()) {
118                 pathArguments.add(parsePathArgument(pathArgument));
119             } else {
120                 pathArguments.add(PathArgumentSerializer.deSerialize(context, pathArgument));
121             }
122         }
123
124         return YangInstanceIdentifier.create(pathArguments);
125     }
126
127     /**
128      * Take the various attributes of a PathArgument and package them up as
129      * protocol buffer attributes.
130      * <p/>
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      */
156     private static Iterable<? extends NormalizedNodeMessages.Attribute> getPathArgumentAttributes(
157         PathArgument pathArgument) {
158         List<NormalizedNodeMessages.Attribute> attributes = new ArrayList<>();
159
160         if (pathArgument instanceof NodeWithValue) {
161             NodeWithValue<?> identifier = (NodeWithValue<?>) pathArgument;
162
163             NormalizedNodeMessages.Attribute attribute =
164                 NormalizedNodeMessages.Attribute.newBuilder()
165                     .setName("name")
166                     .setValue(identifier.getValue().toString())
167                     .setType(identifier.getValue().getClass().getSimpleName())
168                     .build();
169
170             attributes.add(attribute);
171         } else if (pathArgument instanceof NodeIdentifierWithPredicates) {
172             NodeIdentifierWithPredicates identifier = (NodeIdentifierWithPredicates) pathArgument;
173
174             for (QName key : identifier.getKeyValues().keySet()) {
175                 Object value = identifier.getKeyValues().get(key);
176                 NormalizedNodeMessages.Attribute attribute =
177                     NormalizedNodeMessages.Attribute.newBuilder()
178                         .setName(key.toString())
179                         .setValue(value.toString())
180                         .setType(value.getClass().getSimpleName())
181                         .build();
182
183                 attributes.add(attribute);
184
185             }
186
187         } else if (pathArgument instanceof AugmentationIdentifier) {
188             AugmentationIdentifier identifier = (AugmentationIdentifier) pathArgument;
189
190             for (QName key : identifier.getPossibleChildNames()) {
191                 Object value = key;
192                 NormalizedNodeMessages.Attribute attribute =
193                     NormalizedNodeMessages.Attribute.newBuilder()
194                         .setName(key.toString())
195                         .setValue(value.toString())
196                         .setType(value.getClass().getSimpleName())
197                         .build();
198
199                 attributes.add(attribute);
200
201             }
202         }
203
204         return attributes;
205     }
206
207
208     /**
209      * Parse a protocol buffer PathArgument and return an MD-SAL PathArgument.
210      *
211      * @param pathArgument protocol buffer PathArgument
212      * @return MD-SAL PathArgument
213      */
214     private static PathArgument parsePathArgument(
215             NormalizedNodeMessages.PathArgument pathArgument) {
216         if (NodeWithValue.class.getSimpleName().equals(pathArgument.getType())) {
217
218             NodeWithValue<?> nodeWithValue = new NodeWithValue<>(
219                     QNameFactory.create(pathArgument.getNodeType().getValue()),
220                     parseAttribute(pathArgument.getAttributes(0)));
221
222             return nodeWithValue;
223
224         } else if (NodeIdentifierWithPredicates.class.getSimpleName().equals(pathArgument.getType())) {
225
226             NodeIdentifierWithPredicates nodeIdentifierWithPredicates =
227                     new NodeIdentifierWithPredicates(QNameFactory.create(pathArgument.getNodeType().getValue()),
228                             toAttributesMap(pathArgument.getAttributesList()));
229
230             return nodeIdentifierWithPredicates;
231
232         } else if (AugmentationIdentifier.class.getSimpleName().equals(pathArgument.getType())) {
233
234             Set<QName> qnameSet = new HashSet<>();
235
236             for (NormalizedNodeMessages.Attribute attribute : pathArgument.getAttributesList()) {
237                 qnameSet.add(QNameFactory.create(attribute.getValue()));
238             }
239
240             return new AugmentationIdentifier(qnameSet);
241         }
242
243         return NodeIdentifierFactory.getArgument(pathArgument.getValue());
244     }
245
246     private static Map<QName, Object> toAttributesMap(
247         List<NormalizedNodeMessages.Attribute> attributesList) {
248
249         Map<QName, Object> map = new HashMap<>();
250
251         for (NormalizedNodeMessages.Attribute attribute : attributesList) {
252             String name = attribute.getName();
253             Object value = parseAttribute(attribute);
254
255             map.put(QNameFactory.create(name), value);
256         }
257
258         return map;
259     }
260
261     /**
262      * FIXME: This method only covers a subset of values that may go in an InstanceIdentifier.
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 }