2 * Copyright (c) 2015 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.yangtools.yang.parser.stmt.rfc6020;
10 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
12 import java.util.Collection;
15 import java.net.URISyntaxException;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.Date;
19 import java.util.Iterator;
20 import java.util.LinkedList;
21 import java.util.List;
22 import javax.annotation.Nullable;
23 import javax.xml.xpath.XPath;
24 import javax.xml.xpath.XPathExpressionException;
25 import javax.xml.xpath.XPathFactory;
26 import com.google.common.base.CharMatcher;
27 import com.google.common.base.Splitter;
28 import org.opendaylight.yangtools.yang.model.api.Deviation;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.antlr.v4.runtime.tree.TerminalNode;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
33 import org.opendaylight.yangtools.yang.common.QName;
34 import org.opendaylight.yangtools.yang.common.QNameModule;
35 import org.opendaylight.yangtools.yang.common.YangConstants;
36 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
37 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
38 import org.opendaylight.yangtools.yang.model.api.stmt.BelongsToStatement;
39 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
40 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
41 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
42 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
43 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
44 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
45 import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleName;
46 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier;
47 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleIdentifierToModuleQName;
48 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
49 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
50 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
51 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
53 public final class Utils {
55 private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
56 private static final CharMatcher DOUBLE_QUOTE_MATCHER = CharMatcher.is('"');
57 private static final CharMatcher SINGLE_QUOTE_MATCHER = CharMatcher
60 private static final char SEPARATOR_NODENAME = '/';
62 private static final String REGEX_PATH_ABS = "/[^/].*";
67 public static List<String> splitPathToNodeNames(String path) {
69 Splitter keySplitter = Splitter.on(SEPARATOR_NODENAME)
70 .omitEmptyStrings().trimResults();
71 return keySplitter.splitToList(path);
74 public static void validateXPath(String path) {
76 final XPath xPath = XPathFactory.newInstance().newXPath();
80 } catch (XPathExpressionException e) {
81 throw new IllegalArgumentException(
82 "Argument is not valid XPath string", e);
86 public static boolean isXPathAbsolute(String path) {
90 return path.matches(REGEX_PATH_ABS);
93 public static QName trimPrefix(QName identifier) {
94 String prefixedLocalName = identifier.getLocalName();
95 String[] namesParts = prefixedLocalName.split(":");
97 if (namesParts.length == 2) {
98 String localName = namesParts[1];
99 return QName.create(identifier.getModule(), localName);
105 public static boolean isValidStatementDefinition(PrefixToModule prefixes,
106 QNameToStatementDefinition stmtDef, QName identifier) {
107 if (stmtDef.get(identifier) != null) {
110 String prefixedLocalName = identifier.getLocalName();
111 String[] namesParts = prefixedLocalName.split(":");
113 if (namesParts.length == 2) {
114 String prefix = namesParts[0];
115 String localName = namesParts[1];
117 && prefixes.get(prefix) != null
120 YangConstants.RFC6020_YIN_NAMESPACE,
121 localName)) != null) {
129 public static Iterable<QName> parseXPath(StmtContext<?, ?, ?> ctx,
134 List<String> nodeNames = splitPathToNodeNames(path);
135 List<QName> qNames = new ArrayList<>();
137 for (String nodeName : nodeNames) {
139 final QName qName = Utils.qNameFromArgument(ctx, nodeName);
141 } catch (Exception e) {
142 throw new IllegalArgumentException(e);
149 public static String stringFromStringContext(
150 final YangStatementParser.ArgumentContext context) {
151 StringBuilder sb = new StringBuilder();
152 List<TerminalNode> strings = context.STRING();
153 if (strings.isEmpty()) {
154 strings = Arrays.asList(context.IDENTIFIER());
156 for (TerminalNode stringNode : strings) {
157 final String str = stringNode.getText();
158 char firstChar = str.charAt(0);
159 final CharMatcher quoteMatcher;
160 if (SINGLE_QUOTE_MATCHER.matches(firstChar)) {
161 quoteMatcher = SINGLE_QUOTE_MATCHER;
162 } else if (DOUBLE_QUOTE_MATCHER.matches(firstChar)) {
163 quoteMatcher = DOUBLE_QUOTE_MATCHER;
168 sb.append(quoteMatcher.removeFrom(str.substring(1, str.length() - 1)));
170 return sb.toString();
173 public static QName qNameFromArgument(StmtContext<?, ?, ?> ctx, String value) {
176 QNameModule qNameModule = null;
178 qNameModule = QNameModule.create(new URI(""), new Date(0));
179 } catch (URISyntaxException e) {
180 LOG.warn(e.getMessage(), e);
182 String localName = null;
184 String[] namesParts = value.split(":");
185 switch (namesParts.length) {
187 localName = namesParts[0];
189 if (StmtContextUtils.producesDeclared(ctx.getRoot(),
190 ModuleStatement.class)) {
191 prefix = firstAttributeOf(
192 ctx.getRoot().declaredSubstatements(),
193 PrefixStatement.class);
195 .getFromNamespace(PrefixToModule.class, prefix);
197 } else if (StmtContextUtils.producesDeclared(ctx.getRoot(),
198 SubmoduleStatement.class)) {
199 String belongsToModuleName = firstAttributeOf(ctx.getRoot()
200 .declaredSubstatements(), BelongsToStatement.class);
201 qNameModule = ctx.getFromNamespace(
202 ModuleNameToModuleQName.class, belongsToModuleName);
206 prefix = namesParts[0];
207 localName = namesParts[1];
209 ModuleIdentifier impModIdentifier = ctx.getRoot().getFromNamespace(
210 ImpPrefixToModuleIdentifier.class, prefix);
211 qNameModule = ctx.getFromNamespace(
212 ModuleIdentifierToModuleQName.class, impModIdentifier);
214 if (qNameModule == null
215 && StmtContextUtils.producesDeclared(ctx.getRoot(),
216 SubmoduleStatement.class)) {
217 String moduleName = ctx.getRoot().getFromNamespace(
218 BelongsToPrefixToModuleName.class, prefix);
219 qNameModule = ctx.getFromNamespace(
220 ModuleNameToModuleQName.class, moduleName);
228 return QName.create(qNameModule, localName);
232 public static StatementContextBase<?, ?, ?> findCtxOfNodeInSubstatements(
233 StatementContextBase<?, ?, ?> rootStmtCtx,
234 final Iterable<QName> path) {
236 StatementContextBase<?, ?, ?> parent = rootStmtCtx;
238 Iterator<QName> pathIter = path.iterator();
239 while (pathIter.hasNext()) {
240 QName nextPathQName = pathIter.next();
241 StatementContextBase<?, ?, ?> foundSubstatement = getSubstatementByQName(
242 parent, nextPathQName);
244 if (foundSubstatement == null) {
247 if (!pathIter.hasNext()) {
248 return foundSubstatement;
251 parent = foundSubstatement;
257 public static StatementContextBase<?, ?, ?> getSubstatementByQName(
258 StatementContextBase<?, ?, ?> parent, QName nextPathQName) {
260 Collection<StatementContextBase<?, ?, ?>> declaredSubstatement = parent
261 .declaredSubstatements();
262 Collection<StatementContextBase<?, ?, ?>> effectiveSubstatement = parent
263 .effectiveSubstatements();
265 Collection<StatementContextBase<?, ?, ?>> allSubstatements = new LinkedList<>();
266 allSubstatements.addAll(declaredSubstatement);
267 allSubstatements.addAll(effectiveSubstatement);
269 for (StatementContextBase<?, ?, ?> substatement : allSubstatements) {
270 if (nextPathQName.equals(substatement.getStatementArgument())) {
279 public static StatementContextBase<?, ?, ?> findCtxOfNodeInRoot(
280 StatementContextBase<?, ?, ?> rootStmtCtx,
281 final SchemaNodeIdentifier node) {
282 return findCtxOfNodeInSubstatements(rootStmtCtx, node.getPathFromRoot());
285 public static SchemaPath getSchemaPath(StmtContext<?, ?, ?> ctx) {
287 Iterator<Object> argumentsIterator = ctx.getArgumentsFromRoot()
289 argumentsIterator.next(); // skip root argument
291 List<QName> qNamesFromRoot = new LinkedList<>();
293 while (argumentsIterator.hasNext()) {
294 Object argument = argumentsIterator.next();
295 if (argument instanceof QName) {
296 QName qname = (QName) argument;
297 qNamesFromRoot.add(qname);
299 return SchemaPath.SAME;
303 return SchemaPath.create(qNamesFromRoot, true);
306 public static Deviation.Deviate parseDeviateFromString(final String deviate) {
307 if ("not-supported".equals(deviate)) {
308 return Deviation.Deviate.NOT_SUPPORTED;
309 } else if ("add".equals(deviate)) {
310 return Deviation.Deviate.ADD;
311 } else if ("replace".equals(deviate)) {
312 return Deviation.Deviate.REPLACE;
313 } else if ("delete".equals(deviate)) {
314 return Deviation.Deviate.DELETE;
316 throw new IllegalArgumentException(
317 "String %s is not valid deviate argument");