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
8 package org.opendaylight.controller.xml.codec;
10 import com.google.common.base.Preconditions;
11 import com.google.common.base.Splitter;
12 import org.opendaylight.yangtools.yang.common.QName;
13 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
14 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
15 import org.opendaylight.yangtools.yang.model.api.Module;
16 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19 import org.w3c.dom.Element;
22 import java.net.URISyntaxException;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
28 import java.util.Map.Entry;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
32 public final class InstanceIdentifierForXmlCodec {
33 private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
34 private static final Splitter SLASH_SPLITTER = Splitter.on('/');
35 private static final Splitter COLON_SPLITTER = Splitter.on(':');
36 private static final Splitter AT_SPLITTER = Splitter.on('@');
37 private static final Logger logger = LoggerFactory.getLogger(InstanceIdentifierForXmlCodec.class);
39 private InstanceIdentifierForXmlCodec() {
40 throw new UnsupportedOperationException("Utility class");
43 public static YangInstanceIdentifier deserialize(final Element element, final SchemaContext schemaContext) {
44 Preconditions.checkNotNull(element, "Value of element for deserialization can't be null");
45 Preconditions.checkNotNull(schemaContext,
46 "Schema context for deserialization of instance identifier type can't be null");
48 final String valueTrimmed = element.getTextContent().trim();
49 logger.debug("Instance identifier derserialize: splitting the text {} with Slash to find path arguments", valueTrimmed);
50 final Iterator<String> xPathParts = SLASH_SPLITTER.split(valueTrimmed).iterator();
52 // must be at least "/pr:node"
53 if (!xPathParts.hasNext() || !xPathParts.next().isEmpty() || !xPathParts.hasNext()) {
54 logger.debug("Instance identifier derserialize: No path argument found for element.");
58 List<PathArgument> result = new ArrayList<>();
59 while (xPathParts.hasNext()) {
60 String xPathPartTrimmed = xPathParts.next().trim();
62 PathArgument pathArgument = toPathArgument(xPathPartTrimmed, element, schemaContext);
63 if (pathArgument != null) {
64 result.add(pathArgument);
67 return YangInstanceIdentifier.create(result);
70 public static Element serialize(final YangInstanceIdentifier id, final Element element) {
71 Preconditions.checkNotNull(id, "Variable should contain instance of instance identifier and can't be null");
72 Preconditions.checkNotNull(element, "DOM element can't be null");
74 final RandomPrefix prefixes = new RandomPrefix();
75 final String str = XmlUtils.encodeIdentifier(prefixes, id);
77 for (Entry<URI, String> e: prefixes.getPrefixes()) {
78 element.setAttribute("xmlns:" + e.getValue(), e.getKey().toString());
80 element.setTextContent(str);
84 private static String getIdAndPrefixAsStr(final String pathPart) {
85 int predicateStartIndex = pathPart.indexOf('[');
86 return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
89 private static PathArgument toPathArgument(final String xPathArgument, final Element element, final SchemaContext schemaContext) {
90 final QName mainQName = toIdentity(xPathArgument, element, schemaContext);
93 final Matcher matcher = PREDICATE_PATTERN.matcher(xPathArgument);
94 final Map<QName, Object> predicates = new HashMap<>();
95 QName currentQName = mainQName;
97 while (matcher.find()) {
98 final String predicateStr = matcher.group(1).trim();
99 final int indexOfEqualityMark = predicateStr.indexOf('=');
100 if (indexOfEqualityMark != -1) {
101 final Object predicateValue = toPredicateValue(predicateStr.substring(indexOfEqualityMark + 1));
102 if (predicateValue == null) {
106 if (predicateStr.charAt(0) != '.') {
107 // target is not a leaf-list
108 currentQName = toIdentity(predicateStr.substring(0, indexOfEqualityMark), element, schemaContext);
109 if (currentQName == null) {
113 logger.debug("Instance identifier derserialize: finding predicates of node {}", predicateValue);
114 predicates.put(currentQName, predicateValue);
118 if (predicates.isEmpty()) {
119 return new YangInstanceIdentifier.NodeIdentifier(mainQName);
121 return new YangInstanceIdentifier.NodeIdentifierWithPredicates(mainQName, predicates);
126 public static QName toIdentity(final String xPathArgument, final Element element, final SchemaContext schemaContext) {
127 final String xPathPartTrimmed = getIdAndPrefixAsStr(xPathArgument).trim();
128 final Iterator<String> it = COLON_SPLITTER.split(xPathPartTrimmed).iterator();
135 final String prefix = it.next().trim();
136 if (prefix.isEmpty()) {
140 // it is not "prefix:value"
145 final String identifier = it.next().trim();
146 if (identifier.isEmpty()) {
150 URI namespace = null;
151 String namespaceStr = null;
153 namespaceStr = element.getAttribute("xmlns:"+prefix);
154 namespace = new URI(namespaceStr);
155 } catch (URISyntaxException e) {
156 throw new IllegalArgumentException("It wasn't possible to convert " + namespaceStr + " to URI object.");
157 } catch (NullPointerException e) {
158 throw new IllegalArgumentException("I wasn't possible to get namespace for prefix " + prefix);
161 Module module = schemaContext.findModuleByNamespaceAndRevision(namespace, null);
162 return QName.create(module.getQNameModule(), identifier);
165 private static String trimIfEndIs(final String str, final char end) {
166 final int l = str.length() - 1;
167 if (str.charAt(l) != end) {
171 return str.substring(1, l);
174 private static Object toPredicateValue(final String predicatedValue) {
175 logger.debug("Instance identifier derserialize: converting the predicate vstring to object {}", predicatedValue);
176 final String predicatedValueTrimmed = predicatedValue.trim();
177 if (predicatedValue.isEmpty()) {
180 String updatedValue = null;
181 switch (predicatedValueTrimmed.charAt(0)) {
183 updatedValue = trimIfEndIs(predicatedValueTrimmed, '"');
186 updatedValue = trimIfEndIs(predicatedValueTrimmed, '\'');
189 updatedValue = predicatedValueTrimmed;
191 Iterator<String> it = AT_SPLITTER.split(updatedValue).iterator();
197 final String value = it.next().trim();
198 if (value.isEmpty()) {
206 final String type = it.next().trim();
207 if (type.isEmpty()) {
210 Object predicateObject = null;
212 logger.debug("Instance identifier derserialize: converting the predicate value {{}}to correct object type {{}}", value, type);
213 predicateObject = Class.forName(type).getConstructor(String.class).newInstance(value);
214 } catch (Exception e) {
215 logger.error("Could not convert to valid type of value", e);
217 return predicateObject;