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;
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")
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;
for (final StmtContext<?, ?, ?> stmt : stmtContext.declaredSubstatements()) {
if (YangStmtMapping.IF_FEATURE.equals(stmt.getPublicDefinition())) {
containsIfFeature = true;
- if (((Predicate<Set<QName>>) stmt.getStatementArgument()).test(supportedFeatures)) {
+ @SuppressWarnings("unchecked")
+ final Predicate<Set<QName>> argument = (Predicate<Set<QName>>) stmt.coerceStatementArgument();
+ if (argument.test(supportedFeatures)) {
isSupported = true;
} else {
isSupported = false;
requireNonNull(ancestorType);
requireNonNull(ancestorChildType);
- StmtContext<?, ?, ?> current = ctx.getParentContext();
+ StmtContext<?, ?, ?> current = ctx.coerceParentContext();
StmtContext<?, ?, ?> parent = current.getParentContext();
while (parent != null) {
if (ancestorType.equals(current.getPublicDefinition())) {
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());
}
/**
}
final StmtContext<?, ?, ?> listStmtCtx = ctx.getParentContext();
- final StmtContext<Collection<SchemaNodeIdentifier>, ?, ?> keyStmtCtx =
- StmtContextUtils.findFirstDeclaredSubstatement(listStmtCtx, KeyStatement.class);
+ final StmtContext<Collection<SchemaNodeIdentifier>, ?, ?> 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);
}
}
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<Collection<SchemaNodeIdentifier>, ?, ?> keyStmtCtx) {
- for (final SchemaNodeIdentifier keyIdentifier : keyStmtCtx.getStatementArgument()) {
+ for (final SchemaNodeIdentifier keyIdentifier : keyStmtCtx.coerceStatementArgument()) {
if (leafStmtCtx.getStatementArgument().equals(keyIdentifier.getLastComponent())) {
return true;
}
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<? extends StmtContext<?, ?, ?>> 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) {
}
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> revision = getLatestRevision(root.declaredSubstatements());
+ return RevisionSourceIdentifier.create((String) root.getStatementArgument(), revision);
}
- public static Date getLatestRevision(final Iterable<? extends StmtContext<?, ?, ?>> subStmts) {
- Date revision = null;
+ public static Optional<Revision> getLatestRevision(final Iterable<? extends StmtContext<?, ?, ?>> 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;
}
}