ff04373f2c0ad9de09a0979ecc428dee4100e1ce
[netconf.git] / restconf / restconf-common / src / main / java / org / opendaylight / restconf / common / util / RestUtil.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 package org.opendaylight.restconf.common.util;
9
10 import com.google.common.base.Preconditions;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.PushbackInputStream;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Optional;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19 import javax.xml.stream.events.StartElement;
20 import org.opendaylight.restconf.common.util.IdentityValuesDTO.IdentityValue;
21 import org.opendaylight.restconf.common.util.IdentityValuesDTO.Predicate;
22 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
23
24 public final class RestUtil {
25
26     // FIXME: BUG-1275: this is code duplicates data.impl.codec
27
28     public static final String SQUOTE = "'";
29     public static final String DQUOTE = "\"";
30     private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
31
32     public static TypeDefinition<?> resolveBaseTypeFrom(final TypeDefinition<?> type) {
33         TypeDefinition<?> superType = type;
34         while (superType.getBaseType() != null) {
35             superType = superType.getBaseType();
36         }
37         return superType;
38     }
39
40     /**
41      * Utility method to find out if is provided {@link InputStream} empty.
42      *
43      * @param  entityStream {@link InputStream} to be checked if it is empty.
44      * @return Empty Optional if provided input stream is empty or Optional
45      *         containing input stream otherwise.
46      *
47      * @throws IOException if an IO error arises during stream inspection.
48      * @throws NullPointerException if provided stream is null.
49      *
50      */
51     public static Optional<InputStream> isInputStreamEmpty(final InputStream entityStream) throws IOException {
52         Preconditions.checkNotNull(entityStream);
53         final PushbackInputStream pushbackInputStream = new PushbackInputStream(entityStream);
54
55         int firstByte = pushbackInputStream.read();
56         if (firstByte == -1) {
57             return Optional.empty();
58         } else {
59             pushbackInputStream.unread(firstByte);
60             return Optional.of(pushbackInputStream);
61         }
62     }
63
64     public static IdentityValuesDTO asInstanceIdentifier(final String value, final PrefixesMaping prefixMap) {
65         final String valueTrimmed = value.trim();
66         if (!valueTrimmed.startsWith("/")) {
67             return null;
68         }
69         final String[] xPathParts = valueTrimmed.split("/");
70         if (xPathParts.length < 2) { // must be at least "/pr:node"
71             return null;
72         }
73         final IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO(value);
74         for (int i = 1; i < xPathParts.length; i++) {
75             final String xPathPartTrimmed = xPathParts[i].trim();
76
77             final String xPathPartStr = getIdAndPrefixAsStr(xPathPartTrimmed);
78             final IdentityValue identityValue = toIdentity(xPathPartStr, prefixMap);
79             if (identityValue == null) {
80                 return null;
81             }
82
83             final List<Predicate> predicates = toPredicates(xPathPartTrimmed, prefixMap);
84             if (predicates == null) {
85                 return null;
86             }
87             identityValue.setPredicates(predicates);
88
89             identityValuesDTO.add(identityValue);
90         }
91         return identityValuesDTO.getValuesWithNamespaces().isEmpty() ? null : identityValuesDTO;
92     }
93
94     private static String getIdAndPrefixAsStr(final String pathPart) {
95         final int predicateStartIndex = pathPart.indexOf("[");
96         return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
97     }
98
99     private static IdentityValue toIdentity(final String xpathPart, final PrefixesMaping prefixMap) {
100         final String xPathPartTrimmed = xpathPart.trim();
101         if (xPathPartTrimmed.isEmpty()) {
102             return null;
103         }
104         final String[] prefixAndIdentifier = xPathPartTrimmed.split(":");
105         // it is not "prefix:value"
106         if (prefixAndIdentifier.length != 2) {
107             return null;
108         }
109         final String prefix = prefixAndIdentifier[0].trim();
110         final String identifier = prefixAndIdentifier[1].trim();
111         if (prefix.isEmpty() || identifier.isEmpty()) {
112             return null;
113         }
114         final String namespace = prefixMap.getNamespace(prefix);
115         return new IdentityValue(namespace, identifier);
116     }
117
118     private static List<Predicate> toPredicates(final String predicatesStr, final PrefixesMaping prefixMap) {
119         final List<Predicate> result = new ArrayList<>();
120         final List<String> predicates = new ArrayList<>();
121         final Matcher matcher = PREDICATE_PATTERN.matcher(predicatesStr);
122         while (matcher.find()) {
123             predicates.add(matcher.group(1).trim());
124         }
125         for (final String predicate : predicates) {
126             final int indexOfEqualityMark = predicate.indexOf("=");
127             if (indexOfEqualityMark != -1) {
128                 final String predicateValue = toPredicateValue(predicate.substring(indexOfEqualityMark + 1));
129                 if (predicate.startsWith(".")) { // it is leaf-list
130                     if (predicateValue == null) {
131                         return null;
132                     }
133                     result.add(new Predicate(null, predicateValue));
134                 } else {
135                     final IdentityValue identityValue =
136                             toIdentity(predicate.substring(0, indexOfEqualityMark), prefixMap);
137                     if (identityValue == null || predicateValue == null) {
138                         return null;
139                     }
140                     result.add(new Predicate(identityValue, predicateValue));
141                 }
142             }
143         }
144         return result;
145     }
146
147     private static String toPredicateValue(final String predicatedValue) {
148         final String predicatedValueTrimmed = predicatedValue.trim();
149         if ((predicatedValueTrimmed.startsWith(DQUOTE) || predicatedValueTrimmed.startsWith(SQUOTE))
150                 && (predicatedValueTrimmed.endsWith(DQUOTE) || predicatedValueTrimmed.endsWith(SQUOTE))) {
151             return predicatedValueTrimmed.substring(1, predicatedValueTrimmed.length() - 1);
152         }
153         return null;
154     }
155
156     public interface PrefixesMaping {
157         String getNamespace(String prefix);
158     }
159
160     public static class PrefixMapingFromXml implements PrefixesMaping {
161         StartElement startElement = null;
162
163         public PrefixMapingFromXml(final StartElement startElement) {
164             this.startElement = startElement;
165         }
166
167         @Override
168         public String getNamespace(final String prefix) {
169             return startElement.getNamespaceContext().getNamespaceURI(prefix);
170         }
171     }
172
173     public static class PrefixMapingFromJson implements PrefixesMaping {
174
175         @Override
176         public String getNamespace(final String prefix) {
177             return prefix;
178         }
179     }
180
181 }