X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-spi%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fspi%2Fmeta%2FStmtContextUtils.java;h=ce8ea6f8af6fcea5053755089f26457d9996dbee;hb=541fde521d0b4e01e1023be8612d0fcff81a67bc;hp=9c9b8cffc110074c0efc79eac0303dfd9819f62f;hpb=8f2876d895936b36aba1fc3ec65b18900e559184;p=yangtools.git diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java index 9c9b8cffc1..ce8ea6f8af 100644 --- a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java +++ b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java @@ -10,19 +10,17 @@ package org.opendaylight.yangtools.yang.parser.spi.meta; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; -import com.google.common.base.Splitter; +import com.google.common.annotations.Beta; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import java.util.Collection; -import java.util.Date; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; -import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.yangtools.yang.common.Revision; import org.opendaylight.yangtools.yang.common.YangVersion; -import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; @@ -41,17 +39,14 @@ import org.opendaylight.yangtools.yang.model.api.stmt.UnrecognizedStatement; import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleName; -import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier; +import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx; import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName; -import org.opendaylight.yangtools.yang.parser.spi.source.ModuleIdentifierToModuleQName; import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; public final class StmtContextUtils { - public static final Splitter LIST_KEY_SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults(); - private StmtContextUtils() { - throw new UnsupportedOperationException("Utility class"); + // Hidden on purpose } @SuppressWarnings("unchecked") @@ -206,7 +201,7 @@ public final class StmtContextUtils { public static boolean isInExtensionBody(final StmtContext stmtCtx) { StmtContext current = stmtCtx; - while (current.getParentContext().getParentContext() != null) { + while (current.coerceParentContext().getParentContext() != null) { current = current.getParentContext(); if (isUnknownStatement(current)) { return true; @@ -255,7 +250,9 @@ public final class StmtContextUtils { for (final StmtContext stmt : stmtContext.declaredSubstatements()) { if (YangStmtMapping.IF_FEATURE.equals(stmt.getPublicDefinition())) { containsIfFeature = true; - if (((Predicate>) stmt.getStatementArgument()).test(supportedFeatures)) { + @SuppressWarnings("unchecked") + final Predicate> argument = (Predicate>) stmt.coerceStatementArgument(); + if (argument.test(supportedFeatures)) { isSupported = true; } else { isSupported = false; @@ -377,7 +374,7 @@ public final class StmtContextUtils { requireNonNull(ancestorType); requireNonNull(ancestorChildType); - StmtContext current = ctx.getParentContext(); + StmtContext current = ctx.coerceParentContext(); StmtContext parent = current.getParentContext(); while (parent != null) { if (ancestorType.equals(current.getPublicDefinition())) { @@ -407,7 +404,7 @@ public final class StmtContextUtils { public static boolean hasParentOfType(final StmtContext ctx, final StatementDefinition parentType) { requireNonNull(parentType); final StmtContext parentContext = ctx.getParentContext(); - return parentContext != null ? parentType.equals(parentContext.getPublicDefinition()) : false; + return parentContext != null && parentType.equals(parentContext.getPublicDefinition()); } /** @@ -426,15 +423,15 @@ public final class StmtContextUtils { } final StmtContext listStmtCtx = ctx.getParentContext(); - final StmtContext, ?, ?> keyStmtCtx = - StmtContextUtils.findFirstDeclaredSubstatement(listStmtCtx, KeyStatement.class); + final StmtContext, ?, ?> keyStmtCtx = findFirstDeclaredSubstatement( + listStmtCtx, KeyStatement.class); if (YangStmtMapping.LEAF.equals(ctx.getPublicDefinition())) { if (isListKey(ctx, keyStmtCtx)) { disallowIfFeatureAndWhenOnListKeys(ctx); } } else if (YangStmtMapping.USES.equals(ctx.getPublicDefinition())) { - StmtContextUtils.findAllEffectiveSubstatements(listStmtCtx, LeafStatement.class).forEach(leafStmtCtx -> { + findAllEffectiveSubstatements(listStmtCtx, LeafStatement.class).forEach(leafStmtCtx -> { if (isListKey(leafStmtCtx, keyStmtCtx)) { disallowIfFeatureAndWhenOnListKeys(leafStmtCtx); } @@ -443,14 +440,13 @@ public final class StmtContextUtils { } private static boolean isRelevantForIfFeatureAndWhenOnListKeysCheck(final StmtContext ctx) { - return YangVersion.VERSION_1_1.equals(ctx.getRootVersion()) - && StmtContextUtils.hasParentOfType(ctx, YangStmtMapping.LIST) - && StmtContextUtils.findFirstDeclaredSubstatement(ctx.getParentContext(), KeyStatement.class) != null; + return YangVersion.VERSION_1_1.equals(ctx.getRootVersion()) && hasParentOfType(ctx, YangStmtMapping.LIST) + && findFirstDeclaredSubstatement(ctx.coerceParentContext(), KeyStatement.class) != null; } private static boolean isListKey(final StmtContext leafStmtCtx, final StmtContext, ?, ?> keyStmtCtx) { - for (final SchemaNodeIdentifier keyIdentifier : keyStmtCtx.getStatementArgument()) { + for (final SchemaNodeIdentifier keyIdentifier : keyStmtCtx.coerceStatementArgument()) { if (leafStmtCtx.getStatementArgument().equals(keyIdentifier.getLastComponent())) { return true; } @@ -482,36 +478,105 @@ public final class StmtContextUtils { switch (namesParts.length) { case 1: localName = namesParts[0]; - qnameModule = StmtContextUtils.getRootModuleQName(ctx); + qnameModule = getRootModuleQName(ctx); break; default: prefix = namesParts[0]; localName = namesParts[1]; - qnameModule = StmtContextUtils.getModuleQNameByPrefix(ctx, prefix); + qnameModule = getModuleQNameByPrefix(ctx, prefix); // in case of unknown statement argument, we're not going to parse it if (qnameModule == null && isUnknownStatement(ctx)) { localName = value; - qnameModule = StmtContextUtils.getRootModuleQName(ctx); + qnameModule = getRootModuleQName(ctx); } if (qnameModule == null && ctx.getCopyHistory().getLastOperation() == CopyType.ADDED_BY_AUGMENTATION) { ctx = ctx.getOriginalCtx().orElse(null); - qnameModule = StmtContextUtils.getModuleQNameByPrefix(ctx, prefix); + qnameModule = getModuleQNameByPrefix(ctx, prefix); } - break; } - qnameModule = InferenceException.throwIfNull(qnameModule, ctx.getStatementSourceReference(), - "Cannot resolve QNameModule for '%s'", value); + return internedQName(ctx, + InferenceException.throwIfNull(qnameModule, ctx.getStatementSourceReference(), + "Cannot resolve QNameModule for '%s'", value), localName); + } - final QNameModule resultQNameModule; - if (qnameModule.getRevision() == null) { - resultQNameModule = QNameModule.create(qnameModule.getNamespace(), SimpleDateFormatUtil.DEFAULT_DATE_REV) - .intern(); - } else { - resultQNameModule = qnameModule; + /** + * Parse a YANG identifier string in context of a statement. + * + * @param ctx Statement context + * @param str String to be parsed + * @return An interned QName + * @throws NullPointerException if any of the arguments are null + * @throws SourceException if the string is not a valid YANG identifier + */ + public static QName parseIdentifier(final StmtContext ctx, final String str) { + SourceException.throwIf(str.isEmpty(), ctx.getStatementSourceReference(), + "Identifier may not be an empty string"); + return internedQName(ctx, str); + } + + public static QName parseNodeIdentifier(StmtContext ctx, final String prefix, + final String localName) { + final QNameModule module = getModuleQNameByPrefix(ctx, prefix); + if (module != null) { + return internedQName(ctx, module, localName); + } + + if (ctx.getCopyHistory().getLastOperation() == CopyType.ADDED_BY_AUGMENTATION) { + final Optional> optOrigCtx = ctx.getOriginalCtx(); + if (optOrigCtx.isPresent()) { + ctx = optOrigCtx.get(); + final QNameModule origModule = getModuleQNameByPrefix(ctx, prefix); + if (origModule != null) { + return internedQName(ctx, origModule, localName); + } + } + } + + throw new InferenceException(ctx.getStatementSourceReference(), "Cannot resolve QNameModule for '%s'", prefix); + } + + /** + * Parse a YANG node identifier string in context of a statement. + * + * @param ctx Statement context + * @param str String to be parsed + * @return An interned QName + * @throws NullPointerException if any of the arguments are null + * @throws SourceException if the string is not a valid YANG node identifier + */ + public static QName parseNodeIdentifier(final StmtContext ctx, final String str) { + SourceException.throwIf(str.isEmpty(), ctx.getStatementSourceReference(), + "Node identifier may not be an empty string"); + + final int colon = str.indexOf(':'); + if (colon == -1) { + return internedQName(ctx, str); } - return ctx.getFromNamespace(QNameCacheNamespace.class, QName.create(resultQNameModule, localName)); + final String prefix = str.substring(0, colon); + SourceException.throwIf(prefix.isEmpty(), ctx.getStatementSourceReference(), + "String '%s' has an empty prefix", str); + final String localName = str.substring(colon + 1); + SourceException.throwIf(localName.isEmpty(), ctx.getStatementSourceReference(), + "String '%s' has an empty identifier", str); + + return parseNodeIdentifier(ctx, prefix, localName); + } + + private static QName internedQName(final StmtContext ctx, final String localName) { + return internedQName(ctx, getRootModuleQName(ctx), localName); + } + + private static QName internedQName(final StmtContext ctx, final QNameModule module, + final String localName) { + final QName template; + try { + template = QName.create(module, localName); + } catch (IllegalArgumentException e) { + throw new SourceException(ctx.getStatementSourceReference(), e, "Invalid identifier '%s'", localName); + } + return template.intern(); } public static QNameModule getRootModuleQName(final StmtContext ctx) { @@ -533,52 +598,64 @@ public final class StmtContextUtils { } checkArgument(qnameModule != null, "Failed to look up root QNameModule for %s", ctx); - if (qnameModule.getRevision() != null) { - return qnameModule; - } - - return QNameModule.create(qnameModule.getNamespace(), SimpleDateFormatUtil.DEFAULT_DATE_REV).intern(); + return qnameModule; } public static QNameModule getModuleQNameByPrefix(final StmtContext ctx, final String prefix) { - final ModuleIdentifier modId = ctx.getRoot().getFromNamespace(ImpPrefixToModuleIdentifier.class, prefix); - final QNameModule qnameModule = ctx.getFromNamespace(ModuleIdentifierToModuleQName.class, modId); + final StmtContext importedModule = ctx.getRoot().getFromNamespace(ImportPrefixToModuleCtx.class, + prefix); + final QNameModule qnameModule = ctx.getFromNamespace(ModuleCtxToModuleQName.class, importedModule); + if (qnameModule != null) { + return qnameModule; + } - if (qnameModule == null && producesDeclared(ctx.getRoot(), SubmoduleStatement.class)) { + if (producesDeclared(ctx.getRoot(), SubmoduleStatement.class)) { final String moduleName = ctx.getRoot().getFromNamespace(BelongsToPrefixToModuleName.class, prefix); return ctx.getFromNamespace(ModuleNameToModuleQName.class, moduleName); } - return qnameModule; + + return null; } public static SourceIdentifier createSourceIdentifier(final StmtContext root) { final QNameModule qNameModule = root.getFromNamespace(ModuleCtxToModuleQName.class, root); if (qNameModule != null) { // creates SourceIdentifier for a module - return RevisionSourceIdentifier.create((String) root.getStatementArgument(), - qNameModule.getFormattedRevision()); + return RevisionSourceIdentifier.create((String) root.getStatementArgument(), qNameModule.getRevision()); } // creates SourceIdentifier for a submodule - final Date revision = Optional.ofNullable(getLatestRevision(root.declaredSubstatements())) - .orElse(SimpleDateFormatUtil.DEFAULT_DATE_REV); - final String formattedRevision = SimpleDateFormatUtil.getRevisionFormat().format(revision); - return RevisionSourceIdentifier.create((String) root.getStatementArgument(), formattedRevision); + final Optional revision = getLatestRevision(root.declaredSubstatements()); + return RevisionSourceIdentifier.create((String) root.getStatementArgument(), revision); } - public static Date getLatestRevision(final Iterable> subStmts) { - Date revision = null; + public static Optional getLatestRevision(final Iterable> subStmts) { + Revision revision = null; for (final StmtContext subStmt : subStmts) { if (subStmt.getPublicDefinition().getDeclaredRepresentationClass().isAssignableFrom( RevisionStatement.class)) { if (revision == null && subStmt.getStatementArgument() != null) { - revision = (Date) subStmt.getStatementArgument(); - } else if (subStmt.getStatementArgument() != null - && ((Date) subStmt.getStatementArgument()).compareTo(revision) > 0) { - revision = (Date) subStmt.getStatementArgument(); + revision = (Revision) subStmt.getStatementArgument(); + } else { + final Revision subArg = (Revision) subStmt.getStatementArgument(); + if (subArg != null && subArg.compareTo(revision) > 0) { + revision = subArg; + } } } } - return revision; + return Optional.ofNullable(revision); + } + + /** + * Determine if a specific statetement context is a child of a statement context which produces a grouping. + * + * @param stmt Statement to examine + * @return True if parent context is that of a grouping. + */ + @Beta + public static boolean isChildOfGrouping(final StmtContext stmt) { + final StmtContext parent = stmt.getParentContext(); + return parent != null && parent.getPublicDefinition() == YangStmtMapping.GROUPING; } }