2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.controller.cluster.datastore.node.utils.serialization;
11 import com.google.common.base.Preconditions;
12 import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory;
13 import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory;
14 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
15 import org.opendaylight.yangtools.yang.common.QName;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
24 import java.util.Map.Entry;
26 import static org.opendaylight.controller.cluster.datastore.node.utils.serialization.PathArgumentType.getSerializablePathArgumentType;
28 public class PathArgumentSerializer {
29 private static final String REVISION_ARG = "?revision=";
30 private static final Map<Class<?>, PathArgumentAttributesGetter> pathArgumentAttributesGetters = new HashMap<>();
32 public static NormalizedNodeMessages.PathArgument serialize(QNameSerializationContext context,
33 YangInstanceIdentifier.PathArgument pathArgument){
34 Preconditions.checkNotNull(context, "context should not be null");
35 Preconditions.checkNotNull(pathArgument, "pathArgument should not be null");
37 QName nodeType = null;
38 if (!(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier)) {
39 nodeType = pathArgument.getNodeType();
42 NormalizedNodeMessages.PathArgument.Builder builder =
43 NormalizedNodeMessages.PathArgument.newBuilder();
45 NormalizedNodeMessages.PathArgument serializablePathArgument =
47 .setIntType(getSerializablePathArgumentType(pathArgument))
48 .setNodeType(encodeQName(context, nodeType))
49 .addAllAttribute(getPathArgumentAttributes(context, pathArgument))
52 return serializablePathArgument;
56 public static YangInstanceIdentifier.PathArgument deSerialize(QNameDeSerializationContext context,
57 NormalizedNodeMessages.PathArgument pathArgument){
58 Preconditions.checkNotNull(context, "context should not be null");
59 Preconditions.checkNotNull(pathArgument, "pathArgument should not be null");
61 return parsePathArgument(context, pathArgument);
65 private static interface PathArgumentAttributesGetter {
66 Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> get(
67 QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument);
71 pathArgumentAttributesGetters.put(YangInstanceIdentifier.NodeWithValue.class, new PathArgumentAttributesGetter() {
73 public Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> get(
74 QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument) {
76 YangInstanceIdentifier.NodeWithValue identifier
77 = (YangInstanceIdentifier.NodeWithValue) pathArgument;
79 NormalizedNodeMessages.PathArgumentAttribute attribute =
80 buildAttribute(context, null, identifier.getValue());
82 return Arrays.asList(attribute);
86 pathArgumentAttributesGetters.put(YangInstanceIdentifier.NodeIdentifierWithPredicates.class, new PathArgumentAttributesGetter() {
88 public Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> get(
89 QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument) {
91 YangInstanceIdentifier.NodeIdentifierWithPredicates identifier
92 = (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument;
94 Map<QName, Object> keyValues = identifier.getKeyValues();
95 List<NormalizedNodeMessages.PathArgumentAttribute> attributes =
96 new ArrayList<>(keyValues.size());
97 for (Entry<QName, Object> e : keyValues.entrySet()) {
98 NormalizedNodeMessages.PathArgumentAttribute attribute =
99 buildAttribute(context, e.getKey(), e.getValue());
101 attributes.add(attribute);
108 pathArgumentAttributesGetters.put(YangInstanceIdentifier.AugmentationIdentifier.class, new PathArgumentAttributesGetter() {
110 public Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> get(
111 QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument) {
113 YangInstanceIdentifier.AugmentationIdentifier identifier
114 = (YangInstanceIdentifier.AugmentationIdentifier) pathArgument;
116 Set<QName> possibleChildNames = identifier.getPossibleChildNames();
117 List<NormalizedNodeMessages.PathArgumentAttribute> attributes =
118 new ArrayList<>(possibleChildNames.size());
119 for (QName key : possibleChildNames) {
121 NormalizedNodeMessages.PathArgumentAttribute attribute =
122 buildAttribute(context, key, value);
124 attributes.add(attribute);
132 pathArgumentAttributesGetters.put(YangInstanceIdentifier.NodeIdentifier.class, new PathArgumentAttributesGetter() {
134 public Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> get(
135 QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument) {
136 return Collections.emptyList();
141 private static NormalizedNodeMessages.PathArgumentAttribute buildAttribute(
142 QNameSerializationContext context, QName name, Object value) {
143 NormalizedNodeMessages.PathArgumentAttribute.Builder builder =
144 NormalizedNodeMessages.PathArgumentAttribute.newBuilder();
146 builder.setName(encodeQName(context, name));
147 ValueSerializer.serialize(builder, context, value);
149 return builder.build();
153 private static NormalizedNodeMessages.QName.Builder encodeQName(QNameSerializationContext context,
156 return NormalizedNodeMessages.QName.getDefaultInstance().toBuilder();
158 NormalizedNodeMessages.QName.Builder qNameBuilder =
159 NormalizedNodeMessages.QName.newBuilder();
161 qNameBuilder.setNamespace(context.addNamespace(qName.getNamespace()));
163 qNameBuilder.setRevision(context.addRevision(qName.getRevision()));
165 qNameBuilder.setLocalName(context.addLocalName(qName.getLocalName()));
170 private static Iterable<? extends NormalizedNodeMessages.PathArgumentAttribute> getPathArgumentAttributes(
171 QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument) {
173 return pathArgumentAttributesGetters.get(pathArgument.getClass()).get(context, pathArgument);
177 private static String qNameToString(QNameDeSerializationContext context,
178 NormalizedNodeMessages.QName qName){
179 // If this serializer is used qName cannot be null (see encodeQName)
180 // adding null check only in case someone tried to deSerialize a protocol buffer node
181 // that was not serialized using the PathArgumentSerializer
182 // Preconditions.checkNotNull(qName, "qName should not be null");
183 // Preconditions.checkArgument(qName.getNamespace() != -1, "qName.namespace should be valid");
185 String namespace = context.getNamespace(qName.getNamespace());
186 String localName = context.getLocalName(qName.getLocalName());
188 if(qName.getRevision() != -1){
189 String revision = context.getRevision(qName.getRevision());
190 sb = new StringBuilder(namespace.length() + REVISION_ARG.length() + revision.length() +
191 localName.length() + 2);
192 sb.append('(').append(namespace).append(REVISION_ARG).append(
193 revision).append(')').append(localName);
195 sb = new StringBuilder(namespace.length() + localName.length() + 2);
196 sb.append('(').append(namespace).append(')').append(localName);
199 return sb.toString();
203 * Parse a protocol buffer PathArgument and return an MD-SAL PathArgument
205 * @param pathArgument protocol buffer PathArgument
206 * @return MD-SAL PathArgument
208 private static YangInstanceIdentifier.PathArgument parsePathArgument(
209 QNameDeSerializationContext context, NormalizedNodeMessages.PathArgument pathArgument) {
211 switch(PathArgumentType.values()[pathArgument.getIntType()]){
212 case NODE_IDENTIFIER_WITH_VALUE : {
214 YangInstanceIdentifier.NodeWithValue nodeWithValue =
215 new YangInstanceIdentifier.NodeWithValue(
216 QNameFactory.create(qNameToString(context, pathArgument.getNodeType())),
217 parseAttribute(context, pathArgument.getAttribute(0)));
219 return nodeWithValue;
222 case NODE_IDENTIFIER_WITH_PREDICATES : {
224 YangInstanceIdentifier.NodeIdentifierWithPredicates
225 nodeIdentifierWithPredicates =
226 new YangInstanceIdentifier.NodeIdentifierWithPredicates(
227 QNameFactory.create(qNameToString(context, pathArgument.getNodeType())),
228 toAttributesMap(context, pathArgument.getAttributeList()));
230 return nodeIdentifierWithPredicates;
233 case AUGMENTATION_IDENTIFIER: {
235 Set<QName> qNameSet = new HashSet<>();
237 for(NormalizedNodeMessages.PathArgumentAttribute attribute : pathArgument.getAttributeList()){
238 qNameSet.add(QNameFactory.create(qNameToString(context, attribute.getName())));
241 return new YangInstanceIdentifier.AugmentationIdentifier(qNameSet);
245 return NodeIdentifierFactory.getArgument(qNameToString(context,
246 pathArgument.getNodeType()));
252 private static Map<QName, Object> toAttributesMap(
253 QNameDeSerializationContext context,
254 List<NormalizedNodeMessages.PathArgumentAttribute> attributesList) {
256 Map<QName, Object> map;
257 if(attributesList.size() == 1) {
258 NormalizedNodeMessages.PathArgumentAttribute attribute = attributesList.get(0);
259 NormalizedNodeMessages.QName name = attribute.getName();
260 Object value = parseAttribute(context, attribute);
261 map = Collections.singletonMap(QNameFactory.create(qNameToString(context, name)), value);
263 map = new HashMap<>();
265 for(NormalizedNodeMessages.PathArgumentAttribute attribute : attributesList){
266 NormalizedNodeMessages.QName name = attribute.getName();
267 Object value = parseAttribute(context, attribute);
269 map.put(QNameFactory.create(qNameToString(context, name)), value);
276 private static Object parseAttribute(QNameDeSerializationContext context,
277 NormalizedNodeMessages.PathArgumentAttribute attribute){
278 return ValueSerializer.deSerialize(context, attribute);