Merge "Add support for metadata to the Match/Action classes"
[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.cluster.datastore.node.utils.serialization.PathArgumentSerializer;
16 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameDeSerializationContext;
17 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameDeSerializationContextImpl;
18 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameSerializationContext;
19 import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameSerializationContextImpl;
20 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
21 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder;
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32
33 /**
34  * This class contains utility methods for converting an MD-SAL
35  * YangInstanceIdentifier to and from other representations.
36  * <p>
37  * The representations convered for now are,
38  *
39  * <ul>
40  *     <li>String</li>
41  *     <li>Protocol Buffer</li>
42  * </ul>
43  */
44 public class InstanceIdentifierUtils {
45
46     protected static final Logger logger = LoggerFactory
47         .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     private static NormalizedNodeMessages.InstanceIdentifier.Builder toSerializableBuilder(
67             YangInstanceIdentifier path, QNameSerializationContext context) {
68         NormalizedNodeMessages.InstanceIdentifier.Builder builder =
69             NormalizedNodeMessages.InstanceIdentifier.newBuilder();
70
71         try {
72             for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.
73                                             PathArgument pathArgument : path.getPathArguments()) {
74                 NormalizedNodeMessages.PathArgument serializablePathArgument;
75                 if(context == null) {
76                     String nodeType = "";
77                     if(!(pathArgument instanceof YangInstanceIdentifier.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             logger.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<YangInstanceIdentifier.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      *
132      * PathArguments have 4 subtypes and each of the various subtypes have
133      * different attributes
134      * <ul>
135      *     <li>
136      *         NodeIdentifier is the most basic PathArgument. It is used for
137      *         ContainerNode, LeafNode etc and has no attributes
138      *     </li>
139      *     <li>
140      *         NodeWithValue has only a single attribute. It is used for
141      *         LeafListEntryNodes and the attribute it contains is the value
142      *         of the entry
143      *     </li>
144      *     <li>
145      *         NodeIdentifierWithPredicates has a map of attributes.
146      *         It is used to represent a ListItemNode. Each entry
147      *         in the map of attributes represents the key and value of the
148      *         keys in that entry.
149      *     </li>
150      *     <li>
151      *         AugmentationIdentifier has a list of unnamed attributes. Each
152      *         attribute represents the possible children that can go within
153      *         an augmentation entry.
154      *     </li>
155      * </ul>
156      * @param pathArgument
157      * @return
158      */
159     private static Iterable<? extends NormalizedNodeMessages.Attribute> getPathArgumentAttributes(
160         YangInstanceIdentifier.PathArgument pathArgument) {
161         List<NormalizedNodeMessages.Attribute> attributes = new ArrayList<>();
162
163
164
165         if (pathArgument instanceof YangInstanceIdentifier.NodeWithValue) {
166             YangInstanceIdentifier.NodeWithValue identifier
167                 = (YangInstanceIdentifier.NodeWithValue) pathArgument;
168
169             NormalizedNodeMessages.Attribute attribute =
170                 NormalizedNodeMessages.Attribute.newBuilder()
171                     .setName("name")
172                     .setValue(identifier.getValue().toString())
173                     .setType(identifier.getValue().getClass().getSimpleName())
174                     .build();
175
176             attributes.add(attribute);
177         } else if (pathArgument instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) {
178             YangInstanceIdentifier.NodeIdentifierWithPredicates identifier
179                 = (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument;
180
181             for (QName key : identifier.getKeyValues().keySet()) {
182                 Object value = identifier.getKeyValues().get(key);
183                 NormalizedNodeMessages.Attribute attribute =
184                     NormalizedNodeMessages.Attribute.newBuilder()
185                         .setName(key.toString())
186                         .setValue(value.toString())
187                         .setType(value.getClass().getSimpleName())
188                         .build();
189
190                 attributes.add(attribute);
191
192             }
193
194         } else if(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier) {
195             YangInstanceIdentifier.AugmentationIdentifier identifier
196                 = (YangInstanceIdentifier.AugmentationIdentifier) pathArgument;
197
198             for (QName key : identifier.getPossibleChildNames()) {
199                 Object value = key;
200                 NormalizedNodeMessages.Attribute attribute =
201                     NormalizedNodeMessages.Attribute.newBuilder()
202                         .setName(key.toString())
203                         .setValue(value.toString())
204                         .setType(value.getClass().getSimpleName())
205                         .build();
206
207                 attributes.add(attribute);
208
209             }
210         }
211
212         return attributes;
213     }
214
215
216     /**
217      * Parse a protocol buffer PathArgument and return an MD-SAL PathArgument
218      *
219      * @param pathArgument protocol buffer PathArgument
220      * @return MD-SAL PathArgument
221      */
222     private static YangInstanceIdentifier.PathArgument parsePathArgument(
223             NormalizedNodeMessages.PathArgument pathArgument) {
224         if (YangInstanceIdentifier.NodeWithValue.class.getSimpleName().equals(pathArgument.getType())) {
225
226             YangInstanceIdentifier.NodeWithValue nodeWithValue =
227                 new YangInstanceIdentifier.NodeWithValue(
228                     QNameFactory.create(pathArgument.getNodeType().getValue()),
229                     parseAttribute(pathArgument.getAttributes(0)));
230
231             return nodeWithValue;
232
233         } else if(YangInstanceIdentifier.NodeIdentifierWithPredicates.class.getSimpleName().equals(pathArgument.getType())){
234
235             YangInstanceIdentifier.NodeIdentifierWithPredicates
236                 nodeIdentifierWithPredicates =
237                 new YangInstanceIdentifier.NodeIdentifierWithPredicates(
238                     QNameFactory.create(pathArgument.getNodeType().getValue()), toAttributesMap(pathArgument.getAttributesList()));
239
240             return nodeIdentifierWithPredicates;
241
242         } else if(YangInstanceIdentifier.AugmentationIdentifier.class.getSimpleName().equals(pathArgument.getType())){
243
244             Set<QName> qNameSet = new HashSet<>();
245
246             for(NormalizedNodeMessages.Attribute attribute : pathArgument.getAttributesList()){
247                 qNameSet.add(QNameFactory.create(attribute.getValue()));
248             }
249
250             return new YangInstanceIdentifier.AugmentationIdentifier(qNameSet);
251         }
252
253         return NodeIdentifierFactory.getArgument(pathArgument.getValue());
254     }
255
256     private static Map<QName, Object> toAttributesMap(
257         List<NormalizedNodeMessages.Attribute> attributesList) {
258
259         Map<QName, Object> map = new HashMap<>();
260
261         for(NormalizedNodeMessages.Attribute attribute : attributesList){
262             String name = attribute.getName();
263             Object value = parseAttribute(attribute);
264
265             map.put(QNameFactory.create(name), value);
266         }
267
268         return map;
269     }
270
271     /**
272      * FIXME: This method only covers a subset of values that may go in an InstanceIdentifier
273      *
274      * @param attribute
275      * @return
276      */
277     private static Object parseAttribute(NormalizedNodeMessages.Attribute attribute){
278         if(Short.class.getSimpleName().equals(attribute.getType())) {
279             return Short.parseShort(attribute.getValue());
280         } else if(Long.class.getSimpleName().equals(attribute.getType())){
281             return Long.parseLong(attribute.getValue());
282         } else if(Boolean.class.getSimpleName().equals(attribute.getType())){
283             return Boolean.parseBoolean(attribute.getValue());
284         } else if(Integer.class.getSimpleName().equals(attribute.getType())){
285             return Integer.parseInt(attribute.getValue());
286         }
287
288         return attribute.getValue();
289     }
290 }