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.restconf.common.util;
10 import static java.util.Objects.requireNonNull;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.PushbackInputStream;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.Optional;
18 import java.util.regex.Matcher;
19 import java.util.regex.Pattern;
20 import javax.xml.stream.events.StartElement;
21 import org.opendaylight.restconf.common.util.IdentityValuesDTO.IdentityValue;
22 import org.opendaylight.restconf.common.util.IdentityValuesDTO.Predicate;
23 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
25 public final class RestUtil {
27 // FIXME: BUG-1275: this is code duplicates data.impl.codec
29 public static final String SQUOTE = "'";
30 public static final String DQUOTE = "\"";
31 private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
36 public static TypeDefinition<?> resolveBaseTypeFrom(final TypeDefinition<?> type) {
37 TypeDefinition<?> superType = type;
38 while (superType.getBaseType() != null) {
39 superType = superType.getBaseType();
45 * Utility method to find out if is provided {@link InputStream} empty.
47 * @param entityStream {@link InputStream} to be checked if it is empty.
48 * @return Empty Optional if provided input stream is empty or Optional
49 * containing input stream otherwise.
51 * @throws IOException if an IO error arises during stream inspection.
52 * @throws NullPointerException if provided stream is null.
55 public static Optional<InputStream> isInputStreamEmpty(final InputStream entityStream) throws IOException {
56 final PushbackInputStream pushbackInputStream = new PushbackInputStream(requireNonNull(entityStream));
58 int firstByte = pushbackInputStream.read();
59 if (firstByte == -1) {
60 return Optional.empty();
62 pushbackInputStream.unread(firstByte);
63 return Optional.of(pushbackInputStream);
67 public static IdentityValuesDTO asInstanceIdentifier(final String value, final PrefixesMaping prefixMap) {
68 final String valueTrimmed = value.trim();
69 if (!valueTrimmed.startsWith("/")) {
72 final String[] xPathParts = valueTrimmed.split("/");
73 if (xPathParts.length < 2) { // must be at least "/pr:node"
76 final IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO(value);
77 for (int i = 1; i < xPathParts.length; i++) {
78 final String xPathPartTrimmed = xPathParts[i].trim();
80 final String xPathPartStr = getIdAndPrefixAsStr(xPathPartTrimmed);
81 final IdentityValue identityValue = toIdentity(xPathPartStr, prefixMap);
82 if (identityValue == null) {
86 final List<Predicate> predicates = toPredicates(xPathPartTrimmed, prefixMap);
87 if (predicates == null) {
90 identityValue.setPredicates(predicates);
92 identityValuesDTO.add(identityValue);
94 return identityValuesDTO.getValuesWithNamespaces().isEmpty() ? null : identityValuesDTO;
97 private static String getIdAndPrefixAsStr(final String pathPart) {
98 final int predicateStartIndex = pathPart.indexOf("[");
99 return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
102 private static IdentityValue toIdentity(final String xpathPart, final PrefixesMaping prefixMap) {
103 final String xPathPartTrimmed = xpathPart.trim();
104 if (xPathPartTrimmed.isEmpty()) {
107 final String[] prefixAndIdentifier = xPathPartTrimmed.split(":");
108 // it is not "prefix:value"
109 if (prefixAndIdentifier.length != 2) {
112 final String prefix = prefixAndIdentifier[0].trim();
113 final String identifier = prefixAndIdentifier[1].trim();
114 if (prefix.isEmpty() || identifier.isEmpty()) {
117 final String namespace = prefixMap.getNamespace(prefix);
118 return new IdentityValue(namespace, identifier);
121 private static List<Predicate> toPredicates(final String predicatesStr, final PrefixesMaping prefixMap) {
122 final List<Predicate> result = new ArrayList<>();
123 final List<String> predicates = new ArrayList<>();
124 final Matcher matcher = PREDICATE_PATTERN.matcher(predicatesStr);
125 while (matcher.find()) {
126 predicates.add(matcher.group(1).trim());
128 for (final String predicate : predicates) {
129 final int indexOfEqualityMark = predicate.indexOf("=");
130 if (indexOfEqualityMark != -1) {
131 final String predicateValue = toPredicateValue(predicate.substring(indexOfEqualityMark + 1));
132 if (predicate.startsWith(".")) { // it is leaf-list
133 if (predicateValue == null) {
136 result.add(new Predicate(null, predicateValue));
138 final IdentityValue identityValue =
139 toIdentity(predicate.substring(0, indexOfEqualityMark), prefixMap);
140 if (identityValue == null || predicateValue == null) {
143 result.add(new Predicate(identityValue, predicateValue));
150 private static String toPredicateValue(final String predicatedValue) {
151 final String predicatedValueTrimmed = predicatedValue.trim();
152 if ((predicatedValueTrimmed.startsWith(DQUOTE) || predicatedValueTrimmed.startsWith(SQUOTE))
153 && (predicatedValueTrimmed.endsWith(DQUOTE) || predicatedValueTrimmed.endsWith(SQUOTE))) {
154 return predicatedValueTrimmed.substring(1, predicatedValueTrimmed.length() - 1);
159 public interface PrefixesMaping {
160 String getNamespace(String prefix);
163 public static class PrefixMapingFromXml implements PrefixesMaping {
164 StartElement startElement = null;
166 public PrefixMapingFromXml(final StartElement startElement) {
167 this.startElement = startElement;
171 public String getNamespace(final String prefix) {
172 return startElement.getNamespaceContext().getNamespaceURI(prefix);
176 public static class PrefixMapingFromJson implements PrefixesMaping {
179 public String getNamespace(final String prefix) {