Merge branch 'master' of ../controller
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / ArgumentUtils.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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.yangtools.yang.parser.rfc7950.stmt;
9
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.UnresolvedNumber;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
24 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
25 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Utility class for dealing with arguments encountered by StatementSupport classes.
31  */
32 @Beta
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();
36
37     private static final Logger LOG = LoggerFactory.getLogger(ArgumentUtils.class);
38
39     @Regex
40     private static final String PATH_ABS_STR = "/[^/].*";
41     private static final Pattern PATH_ABS = Pattern.compile(PATH_ABS_STR);
42     private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings().trimResults();
43
44     // these objects are to compare whether range has MAX or MIN value
45     // none of these values should appear as Yang number according to spec so they are safe to use
46     private static final BigDecimal YANG_MIN_NUM = BigDecimal.valueOf(-Double.MAX_VALUE);
47     private static final BigDecimal YANG_MAX_NUM = BigDecimal.valueOf(Double.MAX_VALUE);
48
49     private ArgumentUtils() {
50         throw new UnsupportedOperationException();
51     }
52
53     public static int compareNumbers(final Number n1, final Number n2) {
54         final BigDecimal num1 = yangConstraintToBigDecimal(n1);
55         final BigDecimal num2 = yangConstraintToBigDecimal(n2);
56         return new BigDecimal(num1.toString()).compareTo(new BigDecimal(num2.toString()));
57     }
58
59     public static String internBoolean(final String input) {
60         if ("true".equals(input)) {
61             return "true";
62         } else if ("false".equals(input)) {
63             return "false";
64         } else {
65             return input;
66         }
67     }
68
69     public static @NonNull Boolean parseBoolean(final StmtContext<?, ?, ?> ctx, final String input) {
70         if ("true".equals(input)) {
71             return Boolean.TRUE;
72         } else if ("false".equals(input)) {
73             return Boolean.FALSE;
74         } else {
75             final StatementDefinition def = ctx.getPublicDefinition();
76             throw new SourceException(ctx.getStatementSourceReference(),
77                 "Invalid '%s' statement %s '%s', it can be either 'true' or 'false'",
78                 def.getStatementName(), def.getArgumentDefinition().get().getArgumentName(), input);
79         }
80     }
81
82     public static RevisionAwareXPath parseXPath(final StmtContext<?, ?, ?> ctx, final String path) {
83         return XPathSupport.parseXPath(ctx, path);
84     }
85
86     public static boolean isAbsoluteXPath(final String path) {
87         return PATH_ABS.matcher(path).matches();
88     }
89
90     @SuppressWarnings("checkstyle:illegalCatch")
91     public static SchemaNodeIdentifier nodeIdentifierFromPath(final StmtContext<?, ?, ?> ctx, final String path) {
92         // FIXME: is the path trimming really necessary??
93         final List<QName> qNames = new ArrayList<>();
94         for (final String nodeName : SLASH_SPLITTER.split(trimSingleLastSlashFromXPath(path))) {
95             try {
96                 qNames.add(StmtContextUtils.parseNodeIdentifier(ctx, nodeName));
97             } catch (final RuntimeException e) {
98                 throw new SourceException(ctx.getStatementSourceReference(), e,
99                         "Failed to parse node '%s' in path '%s'", nodeName, path);
100             }
101         }
102
103         return SchemaNodeIdentifier.create(qNames, PATH_ABS.matcher(path).matches());
104     }
105
106     private static String trimSingleLastSlashFromXPath(final String path) {
107         return path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
108     }
109
110     private static BigDecimal yangConstraintToBigDecimal(final Number number) {
111         if (UnresolvedNumber.max().equals(number)) {
112             return YANG_MAX_NUM;
113         }
114         if (UnresolvedNumber.min().equals(number)) {
115             return YANG_MIN_NUM;
116         }
117
118         return new BigDecimal(number.toString());
119     }
120 }