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=a43313d2243f8e43429e6f70e05947f9c1d24727;hb=refs%2Fchanges%2F15%2F94015%2F7;hp=e4cbe0dda583c18ebedaf7e317e98790f08f8cff;hpb=20216a64f35c0b0ea7a1911df5fbed90e1f045b5;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 e4cbe0dda5..a43313d224 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,44 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt; -import static org.opendaylight.yangtools.yang.common.YangConstants.RFC6020_YANG_NAMESPACE_STRING; -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.eclipse.jdt.annotation.NonNull; 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.meta.StatementDefinition; 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) { @@ -90,80 +63,51 @@ public final class ArgumentUtils { } } - public static @Nonnull Boolean parseBoolean(final StmtContext ctx, final String input) { + 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); + final StatementDefinition def = ctx.publicDefinition(); + throw new SourceException(ctx, "Invalid '%s' statement %s '%s', it can be either 'true' or 'false'", + def.getStatementName(), def.getArgumentDefinition().get().getArgumentName(), input); } } - 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_STRING, 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 boolean isAbsoluteXPath(final String path) { + return PATH_ABS.matcher(path).matches(); + } - return new RevisionAwareXPathImpl(path, PATH_ABS.matcher(path).matches()); + 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 Descendant parseDescendantSchemaNodeIdentifier(final StmtContext ctx, final String str) { + // FIXME: this does accept a leading slash + return Descendant.of(parseNodeIdentifiers(ctx, str)); } - @SuppressWarnings("checkstyle:illegalCatch") 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") + 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) {