Merge "BUG-1845: implement proper shutdown sequence"
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / main / java / org / opendaylight / controller / cluster / datastore / node / utils / serialization / PathArgumentSerializer.java
1 /*
2  * Copyright (c) 2014 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.node.utils.serialization;
10
11 import com.google.common.base.Preconditions;
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
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26
27 import static org.opendaylight.controller.cluster.datastore.node.utils.serialization.PathArgumentType.getSerializablePathArgumentType;
28
29 public class PathArgumentSerializer {
30     private static final String REVISION_ARG = "?revision=";
31     private static final Map<Class, PathArgumentAttributesGetter> pathArgumentAttributesGetters = new HashMap<>();
32
33     public static NormalizedNodeMessages.PathArgument serialize(NormalizedNodeSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument){
34         Preconditions.checkNotNull(context, "context should not be null");
35         Preconditions.checkNotNull(pathArgument, "pathArgument should not be null");
36
37         QName nodeType = null;
38         if (!(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier)) {
39             nodeType = pathArgument.getNodeType();
40         }
41
42         NormalizedNodeMessages.PathArgument.Builder builder =
43             NormalizedNodeMessages.PathArgument.newBuilder();
44
45         NormalizedNodeMessages.PathArgument serializablePathArgument =
46             builder
47                 .setIntType(getSerializablePathArgumentType(pathArgument))
48                 .setNodeType(encodeQName(context, nodeType))
49                 .addAllAttribute(getPathArgumentAttributes(context, pathArgument))
50                 .build();
51
52         return serializablePathArgument;
53     }
54
55
56     public static YangInstanceIdentifier.PathArgument deSerialize(NormalizedNodeDeSerializationContext context, NormalizedNodeMessages.PathArgument pathArgument){
57         Preconditions.checkNotNull(context, "context should not be null");
58         Preconditions.checkNotNull(pathArgument, "pathArgument should not be null");
59
60         return parsePathArgument(context, pathArgument);
61     }
62
63
64     private static interface PathArgumentAttributesGetter {
65         Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> get(NormalizedNodeSerializationContext context,
66             YangInstanceIdentifier.PathArgument pathArgument);
67     }
68
69     static {
70         pathArgumentAttributesGetters.put(YangInstanceIdentifier.NodeWithValue.class, new PathArgumentAttributesGetter() {
71             @Override
72             public Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> get(
73                 NormalizedNodeSerializationContext context,
74                 YangInstanceIdentifier.PathArgument pathArgument) {
75                 List<NormalizedNodeMessages.PathArgumentAttribute> attributes =
76                     new ArrayList<>();
77
78                 YangInstanceIdentifier.NodeWithValue identifier
79                     = (YangInstanceIdentifier.NodeWithValue) pathArgument;
80
81                 NormalizedNodeMessages.PathArgumentAttribute attribute =
82                     buildAttribute(context, null, identifier.getValue());
83
84                 attributes.add(attribute);
85
86                 return attributes;
87
88             }
89         });
90
91         pathArgumentAttributesGetters.put(YangInstanceIdentifier.NodeIdentifierWithPredicates.class, new PathArgumentAttributesGetter() {
92             @Override
93             public Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> get(
94                 NormalizedNodeSerializationContext context,
95                 YangInstanceIdentifier.PathArgument pathArgument) {
96
97                 List<NormalizedNodeMessages.PathArgumentAttribute> attributes =
98                     new ArrayList<>();
99
100                 YangInstanceIdentifier.NodeIdentifierWithPredicates identifier
101                     = (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument;
102
103                 for (QName key : identifier.getKeyValues().keySet()) {
104                     Object value = identifier.getKeyValues().get(key);
105                     NormalizedNodeMessages.PathArgumentAttribute attribute =
106                         buildAttribute(context, key, value);
107
108                     attributes.add(attribute);
109
110                 }
111
112                 return attributes;
113
114             }
115         });
116
117         pathArgumentAttributesGetters.put(YangInstanceIdentifier.AugmentationIdentifier.class, new PathArgumentAttributesGetter() {
118             @Override
119             public Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> get(
120                 NormalizedNodeSerializationContext context,
121                 YangInstanceIdentifier.PathArgument pathArgument) {
122
123                 List<NormalizedNodeMessages.PathArgumentAttribute> attributes =
124                     new ArrayList<>();
125
126                 YangInstanceIdentifier.AugmentationIdentifier identifier
127                     = (YangInstanceIdentifier.AugmentationIdentifier) pathArgument;
128
129                 for (QName key : identifier.getPossibleChildNames()) {
130                     Object value = key;
131                     NormalizedNodeMessages.PathArgumentAttribute attribute =
132                         buildAttribute(context, key, value);
133
134                     attributes.add(attribute);
135
136                 }
137
138                 return attributes;
139
140             }
141         });
142
143
144         pathArgumentAttributesGetters.put(YangInstanceIdentifier.NodeIdentifier.class, new PathArgumentAttributesGetter() {
145             @Override
146             public Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> get(
147                 NormalizedNodeSerializationContext context,
148                 YangInstanceIdentifier.PathArgument pathArgument) {
149                 return Collections.emptyList();
150             }
151         });
152     }
153
154     private static NormalizedNodeMessages.PathArgumentAttribute buildAttribute(NormalizedNodeSerializationContext context,QName name, Object value){
155         NormalizedNodeMessages.PathArgumentAttribute.Builder builder =
156             NormalizedNodeMessages.PathArgumentAttribute.newBuilder();
157
158         builder.setName(encodeQName(context, name));
159         ValueSerializer.serialize(builder, context, value);
160
161         return builder.build();
162
163     }
164
165     private static NormalizedNodeMessages.QName.Builder encodeQName(NormalizedNodeSerializationContext context, QName qName){
166         if(qName == null){
167             return NormalizedNodeMessages.QName.getDefaultInstance().toBuilder();
168         }
169         NormalizedNodeMessages.QName.Builder qNameBuilder =
170             NormalizedNodeMessages.QName.newBuilder();
171
172         qNameBuilder.setNamespace(context.addNamespace(qName.getNamespace()));
173
174         qNameBuilder.setRevision(context.addRevision(qName.getRevision()));
175
176         qNameBuilder.setLocalName(context.addLocalName(qName.getLocalName()));
177
178         return qNameBuilder;
179     }
180
181     private static Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> getPathArgumentAttributes(
182             NormalizedNodeSerializationContext context,
183             YangInstanceIdentifier.PathArgument pathArgument) {
184
185         return pathArgumentAttributesGetters.get(pathArgument.getClass()).get(context, pathArgument);
186
187     }
188
189
190     private static String qNameToString(NormalizedNodeDeSerializationContext context,
191         NormalizedNodeMessages.QName qName){
192         // If this serializer is used qName cannot be null (see encodeQName)
193         // adding null check only in case someone tried to deSerialize a protocol buffer node
194         // that was not serialized using the PathArgumentSerializer
195 //        Preconditions.checkNotNull(qName, "qName should not be null");
196 //        Preconditions.checkArgument(qName.getNamespace() != -1, "qName.namespace should be valid");
197
198         String namespace = context.getNamespace(qName.getNamespace());
199         String localName = context.getLocalName(qName.getLocalName());
200         StringBuilder sb;
201         if(qName.getRevision() != -1){
202             String revision = context.getRevision(qName.getRevision());
203             sb = new StringBuilder(namespace.length() + REVISION_ARG.length() + revision.length() +
204                     localName.length() + 2);
205             sb.append('(').append(namespace).append(REVISION_ARG).append(
206                 revision).append(')').append(localName);
207         } else {
208             sb = new StringBuilder(namespace.length() + localName.length() + 2);
209             sb.append('(').append(namespace).append(')').append(localName);
210         }
211
212         return sb.toString();
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(
222         NormalizedNodeDeSerializationContext context,
223         NormalizedNodeMessages.PathArgument pathArgument) {
224
225         switch(PathArgumentType.values()[pathArgument.getIntType()]){
226             case NODE_IDENTIFIER_WITH_VALUE : {
227
228                 YangInstanceIdentifier.NodeWithValue nodeWithValue =
229                     new YangInstanceIdentifier.NodeWithValue(
230                         QNameFactory.create(qNameToString(context, pathArgument.getNodeType())),
231                         parseAttribute(context, pathArgument.getAttribute(0)));
232
233                 return nodeWithValue;
234             }
235
236             case NODE_IDENTIFIER_WITH_PREDICATES : {
237
238                 YangInstanceIdentifier.NodeIdentifierWithPredicates
239                     nodeIdentifierWithPredicates =
240                     new YangInstanceIdentifier.NodeIdentifierWithPredicates(
241                         QNameFactory.create(qNameToString(context, pathArgument.getNodeType())),
242                         toAttributesMap(context, pathArgument.getAttributeList()));
243
244                 return nodeIdentifierWithPredicates;
245             }
246
247             case AUGMENTATION_IDENTIFIER: {
248
249                 Set<QName> qNameSet = new HashSet<>();
250
251                 for(NormalizedNodeMessages.PathArgumentAttribute attribute : pathArgument.getAttributeList()){
252                     qNameSet.add(QNameFactory.create(qNameToString(context, attribute.getName())));
253                 }
254
255                 return new YangInstanceIdentifier.AugmentationIdentifier(qNameSet);
256
257             }
258             default: {
259                 return NodeIdentifierFactory.getArgument(qNameToString(context,
260                     pathArgument.getNodeType()));
261             }
262
263         }
264     }
265
266     private static Map<QName, Object> toAttributesMap(
267         NormalizedNodeDeSerializationContext context,
268         List<NormalizedNodeMessages.PathArgumentAttribute> attributesList) {
269
270         Map<QName, Object> map;
271         if(attributesList.size() == 1) {
272             NormalizedNodeMessages.PathArgumentAttribute attribute = attributesList.get(0);
273             NormalizedNodeMessages.QName name = attribute.getName();
274             Object value = parseAttribute(context, attribute);
275             map = Collections.singletonMap(QNameFactory.create(qNameToString(context, name)), value);
276         } else {
277             map = new HashMap<>();
278
279             for(NormalizedNodeMessages.PathArgumentAttribute attribute : attributesList){
280                 NormalizedNodeMessages.QName name = attribute.getName();
281                 Object value = parseAttribute(context, attribute);
282
283                 map.put(QNameFactory.create(qNameToString(context, name)), value);
284             }
285         }
286
287         return map;
288     }
289
290     private static Object parseAttribute(NormalizedNodeDeSerializationContext context, NormalizedNodeMessages.PathArgumentAttribute attribute){
291         return ValueSerializer.deSerialize(context, attribute);
292     }
293
294 }