X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-rfc7950%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Frfc7950%2Fstmt%2FArgumentUtils.java;h=8ac80fb539e55fff655051c56c5ce14325148975;hb=e5e06d81bed0a7cb520e94a4b018d0e2bb7f0c62;hp=7a2b0c843627b5fead0f341c73b379021162a343;hpb=1cc6359e5bae1459582e9262a24ca56f23bcc70f;p=yangtools.git diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/ArgumentUtils.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/ArgumentUtils.java index 7a2b0c8436..8ac80fb539 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/ArgumentUtils.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/ArgumentUtils.java @@ -7,71 +7,42 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt; -import static org.opendaylight.yangtools.yang.common.YangConstants.RFC6020_YANG_NAMESPACE; -import static org.opendaylight.yangtools.yang.common.YangConstants.YANG_XPATH_FUNCTIONS_PREFIX; - import com.google.common.annotations.Beta; import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableBiMap; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.Nonnull; -import javax.annotation.RegEx; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; +import org.checkerframework.checker.regex.qual.Regex; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.YangVersion; -import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath; import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Descendant; import org.opendaylight.yangtools.yang.model.api.stmt.UnresolvedNumber; -import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** - * Utility class for dealing with arguments encountered by StatementSupport classes. Note that using this class may - * result in thread-local state getting attached. To clean up this state, please invoke - * {@link #detachFromCurrentThread()} when appropriate. + * Utility class for dealing with arguments encountered by StatementSupport classes. */ @Beta public final class ArgumentUtils { public static final Splitter PIPE_SPLITTER = Splitter.on('|').trimResults(); public static final Splitter TWO_DOTS_SPLITTER = Splitter.on("..").trimResults(); - private static final Logger LOG = LoggerFactory.getLogger(ArgumentUtils.class); - - @RegEx - private static final String YANG_XPATH_FUNCTIONS_STRING = - "(re-match|deref|derived-from(-or-self)?|enum-value|bit-is-set)([ \t\r\n]*)(\\()"; - private static final Pattern YANG_XPATH_FUNCTIONS_PATTERN = Pattern.compile(YANG_XPATH_FUNCTIONS_STRING); - - @RegEx + @Regex private static final String PATH_ABS_STR = "/[^/].*"; private static final Pattern PATH_ABS = Pattern.compile(PATH_ABS_STR); private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings().trimResults(); - // XPathFactory is not thread-safe, rather than locking around a shared instance, we use a thread-local one. - private static final ThreadLocal XPATH_FACTORY = new ThreadLocal() { - @Override - protected XPathFactory initialValue() { - return XPathFactory.newInstance(); - } - }; - // these objects are to compare whether range has MAX or MIN value // none of these values should appear as Yang number according to spec so they are safe to use private static final BigDecimal YANG_MIN_NUM = BigDecimal.valueOf(-Double.MAX_VALUE); private static final BigDecimal YANG_MAX_NUM = BigDecimal.valueOf(Double.MAX_VALUE); private ArgumentUtils() { - throw new UnsupportedOperationException(); + // Hidden on purpose } public static int compareNumbers(final Number n1, final Number n2) { @@ -80,90 +51,39 @@ public final class ArgumentUtils { return new BigDecimal(num1.toString()).compareTo(new BigDecimal(num2.toString())); } - public static String internBoolean(final String input) { - if ("true".equals(input)) { - return "true"; - } else if ("false".equals(input)) { - return "false"; - } else { - return input; - } + public static boolean isAbsoluteXPath(final String path) { + return PATH_ABS.matcher(path).matches(); } - public static @Nonnull Boolean parseBoolean(final StmtContext ctx, final String input) { - if ("true".equals(input)) { - return Boolean.TRUE; - } else if ("false".equals(input)) { - return Boolean.FALSE; - } else { - throw new SourceException(ctx.getStatementSourceReference(), - "Invalid '%s' statement %s '%s', it can be either 'true' or 'false'", - ctx.getPublicDefinition().getStatementName(), ctx.getPublicDefinition().getArgumentName(), input); - } + public static Absolute parseAbsoluteSchemaNodeIdentifier(final StmtContext ctx, final String str) { + // FIXME: this does accept check for a leading slash + return Absolute.of(parseNodeIdentifiers(ctx, str)); } - public static RevisionAwareXPath parseXPath(final StmtContext ctx, final String path) { - final XPath xPath = XPATH_FACTORY.get().newXPath(); - xPath.setNamespaceContext(StmtNamespaceContext.create(ctx, - ImmutableBiMap.of(RFC6020_YANG_NAMESPACE.toString(), YANG_XPATH_FUNCTIONS_PREFIX))); - - final String trimmed = trimSingleLastSlashFromXPath(path); - try { - // XPath extension functions have to be prefixed - // yang-specific XPath functions are in fact extended functions, therefore we have to add - // "yang" prefix to them so that they can be properly validated with the XPath.compile() method - // the "yang" prefix is bound to RFC6020 YANG namespace - final String prefixedXPath = addPrefixToYangXPathFunctions(trimmed, ctx); - // TODO: we could capture the result and expose its 'evaluate' method - xPath.compile(prefixedXPath); - } catch (final XPathExpressionException e) { - LOG.warn("Argument \"{}\" is not valid XPath string at \"{}\"", path, ctx.getStatementSourceReference(), e); - } + public static Descendant parseDescendantSchemaNodeIdentifier(final StmtContext ctx, final String str) { + // FIXME: this does accept a leading slash + return Descendant.of(parseNodeIdentifiers(ctx, str)); + } - return new RevisionAwareXPathImpl(path, PATH_ABS.matcher(path).matches()); + public static SchemaNodeIdentifier nodeIdentifierFromPath(final StmtContext ctx, final String path) { + final List qnames = parseNodeIdentifiers(ctx, path); + return PATH_ABS.matcher(path).matches() ? Absolute.of(qnames) : Descendant.of(qnames); } @SuppressWarnings("checkstyle:illegalCatch") - public static SchemaNodeIdentifier nodeIdentifierFromPath(final StmtContext ctx, final String path) { + private static List parseNodeIdentifiers(final StmtContext ctx, final String path) { // FIXME: is the path trimming really necessary?? - final List qNames = new ArrayList<>(); + final List qnames = new ArrayList<>(); for (final String nodeName : SLASH_SPLITTER.split(trimSingleLastSlashFromXPath(path))) { try { - final QName qName = StmtContextUtils.qnameFromArgument(ctx, nodeName); - qNames.add(qName); + qnames.add(StmtContextUtils.parseNodeIdentifier(ctx, nodeName)); } catch (final RuntimeException e) { - throw new SourceException(ctx.getStatementSourceReference(), e, - "Failed to parse node '%s' in path '%s'", nodeName, path); - } - } - - return SchemaNodeIdentifier.create(qNames, PATH_ABS.matcher(path).matches()); - } - - /** - * Cleanup any resources attached to the current thread. Threads interacting with this class can cause thread-local - * caches to them. Invoke this method if you want to detach those resources. - */ - public static void detachFromCurrentThread() { - XPATH_FACTORY.remove(); - } - - private static String addPrefixToYangXPathFunctions(final String path, final StmtContext ctx) { - if (ctx.getRootVersion() == YangVersion.VERSION_1_1) { - // FIXME once Java 9 is available, change this to StringBuilder as Matcher.appendReplacement() and - // Matcher.appendTail() will accept StringBuilder parameter in Java 9 - final StringBuffer result = new StringBuffer(); - final String prefix = YANG_XPATH_FUNCTIONS_PREFIX + ":"; - final Matcher matcher = YANG_XPATH_FUNCTIONS_PATTERN.matcher(path); - while (matcher.find()) { - matcher.appendReplacement(result, prefix + matcher.group()); + throw new SourceException(ctx, e, "Failed to parse node '%s' in path '%s'", nodeName, path); } - - matcher.appendTail(result); - return result.toString(); } - return path; + SourceException.throwIf(qnames.isEmpty(), ctx, "Schema node identifier must not be empty"); + return qnames; } private static String trimSingleLastSlashFromXPath(final String path) {