2 * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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.rfc7950.stmt;
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Splitter;
12 import java.math.BigDecimal;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.regex.Pattern;
16 import org.checkerframework.checker.regex.qual.Regex;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
20 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
21 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
22 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
23 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Descendant;
24 import org.opendaylight.yangtools.yang.model.api.stmt.UnresolvedNumber;
25 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
26 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
27 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
30 * Utility class for dealing with arguments encountered by StatementSupport classes.
33 public final class ArgumentUtils {
34 public static final Splitter PIPE_SPLITTER = Splitter.on('|').trimResults();
35 public static final Splitter TWO_DOTS_SPLITTER = Splitter.on("..").trimResults();
38 private static final String PATH_ABS_STR = "/[^/].*";
39 private static final Pattern PATH_ABS = Pattern.compile(PATH_ABS_STR);
40 private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings().trimResults();
42 // these objects are to compare whether range has MAX or MIN value
43 // none of these values should appear as Yang number according to spec so they are safe to use
44 private static final BigDecimal YANG_MIN_NUM = BigDecimal.valueOf(-Double.MAX_VALUE);
45 private static final BigDecimal YANG_MAX_NUM = BigDecimal.valueOf(Double.MAX_VALUE);
47 private ArgumentUtils() {
51 public static int compareNumbers(final Number n1, final Number n2) {
52 final BigDecimal num1 = yangConstraintToBigDecimal(n1);
53 final BigDecimal num2 = yangConstraintToBigDecimal(n2);
54 return new BigDecimal(num1.toString()).compareTo(new BigDecimal(num2.toString()));
57 public static String internBoolean(final String input) {
58 if ("true".equals(input)) {
60 } else if ("false".equals(input)) {
67 public static @NonNull Boolean parseBoolean(final StmtContext<?, ?, ?> ctx, final String input) {
68 if ("true".equals(input)) {
70 } else if ("false".equals(input)) {
73 final StatementDefinition def = ctx.getPublicDefinition();
74 throw new SourceException(ctx.getStatementSourceReference(),
75 "Invalid '%s' statement %s '%s', it can be either 'true' or 'false'",
76 def.getStatementName(), def.getArgumentDefinition().get().getArgumentName(), input);
80 public static RevisionAwareXPath parseXPath(final StmtContext<?, ?, ?> ctx, final String path) {
81 return XPathSupport.parseXPath(ctx, path);
84 public static boolean isAbsoluteXPath(final String path) {
85 return PATH_ABS.matcher(path).matches();
88 public static Descendant parseDescendantSchemaNodeIdentifier(final StmtContext<?, ?, ?> ctx, final String str) {
89 // FIXME: this does accept a leading slash
90 return Descendant.of(parseNodeIdentifiers(ctx, str));
93 public static SchemaNodeIdentifier nodeIdentifierFromPath(final StmtContext<?, ?, ?> ctx, final String path) {
94 final List<QName> qnames = parseNodeIdentifiers(ctx, path);
95 return PATH_ABS.matcher(path).matches() ? Absolute.of(qnames) : Descendant.of(qnames);
98 @SuppressWarnings("checkstyle:illegalCatch")
99 private static List<QName> parseNodeIdentifiers(final StmtContext<?, ?, ?> ctx, final String path) {
100 // FIXME: is the path trimming really necessary??
101 final List<QName> qnames = new ArrayList<>();
102 for (final String nodeName : SLASH_SPLITTER.split(trimSingleLastSlashFromXPath(path))) {
104 qnames.add(StmtContextUtils.parseNodeIdentifier(ctx, nodeName));
105 } catch (final RuntimeException e) {
106 throw new SourceException(ctx.getStatementSourceReference(), e,
107 "Failed to parse node '%s' in path '%s'", nodeName, path);
111 if (qnames.isEmpty()) {
112 throw new SourceException("Schema node identifier must not be empty", ctx.getStatementSourceReference());
117 private static String trimSingleLastSlashFromXPath(final String path) {
118 return path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
121 private static BigDecimal yangConstraintToBigDecimal(final Number number) {
122 if (UnresolvedNumber.max().equals(number)) {
125 if (UnresolvedNumber.min().equals(number)) {
129 return new BigDecimal(number.toString());