*/
package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
+import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
+import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeAwareEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
/**
* Base stateless superclass for statements which (logically) always have an associated {@link DeclaredStatement}. This
@Override
public abstract @NonNull D getDeclared();
+ /**
+ * Base stateless superclass form {@link SchemaTreeAwareEffectiveStatement}s. It maintains the contents of schema
+ * tree namespace based of effective substatements.
+ *
+ * @param <A> Argument type ({@link Void} if statement does not have argument.)
+ * @param <D> Class representing declared version of this statement.
+ * @param <E> Class representing effective version of this statement.
+ */
+ public abstract static class WithSchemaTree<A, D extends DeclaredStatement<A>,
+ E extends SchemaTreeAwareEffectiveStatement<A, D>> extends AbstractDeclaredEffectiveStatement<A, D> {
+ @Override
+ @SuppressWarnings("unchecked")
+ protected <K, V, N extends IdentifierNamespace<K, V>> Optional<? extends Map<K, V>> getNamespaceContents(
+ final Class<N> namespace) {
+ if (SchemaTreeAwareEffectiveStatement.Namespace.class.equals(namespace)) {
+ return Optional.of((Map<K, V>) schemaTreeNamespace());
+ }
+ return super.getNamespaceContents(namespace);
+ }
+
+ /**
+ * Indexing support for {@link DataNodeContainer#findDataChildByName(QName)}.
+ */
+ protected final Optional<DataSchemaNode> findDataSchemaNode(final QName name) {
+ // Only DataNodeContainer subclasses should be calling this method
+ verify(this instanceof DataNodeContainer);
+ final SchemaTreeEffectiveStatement<?> child = schemaTreeNamespace().get(requireNonNull(name));
+ return child instanceof DataSchemaNode ? Optional.of((DataSchemaNode) child) : Optional.empty();
+ }
+
+ protected abstract ImmutableMap<QName, SchemaTreeEffectiveStatement<?>> schemaTreeNamespace();
+ }
+
+ /**
+ * Base stateless superclass form {@link DataTreeAwareEffectiveStatement}s. It maintains the contents of data tree
+ * namespace based of effective substatements.
+ *
+ * @param <A> Argument type ({@link Void} if statement does not have argument.)
+ * @param <D> Class representing declared version of this statement.
+ * @param <E> Class representing effective version of this statement.
+ */
+ public abstract static class WithDataTree<A, D extends DeclaredStatement<A>,
+ E extends DataTreeAwareEffectiveStatement<A, D>> extends WithSchemaTree<A, D, E> {
+ @Override
+ @SuppressWarnings("unchecked")
+ protected <K, V, N extends IdentifierNamespace<K, V>> Optional<? extends Map<K, V>> getNamespaceContents(
+ final Class<N> namespace) {
+ if (DataTreeAwareEffectiveStatement.Namespace.class.equals(namespace)) {
+ return Optional.of((Map<K, V>) dataTreeNamespace());
+ }
+ return super.getNamespaceContents(namespace);
+ }
+
+ protected abstract ImmutableMap<QName, DataTreeEffectiveStatement<?>> dataTreeNamespace();
+ }
+
/**
* A stateful version of {@link AbstractDeclaredEffectiveStatement}, which holds (and requires) a declared
* statement.
return getDeclared().argument();
}
}
+
+ /**
+ * Stateful version of {@link WithSchemaTree}. Schema tree namespace is eagerly instantiated (and checked).
+ *
+ * @param <A> Argument type ({@link Void} if statement does not have argument.)
+ * @param <D> Class representing declared version of this statement.
+ * @param <E> Class representing effective version of this statement.
+ */
+ public abstract static class DefaultWithSchemaTree<A, D extends DeclaredStatement<A>,
+ E extends SchemaTreeAwareEffectiveStatement<A, D>> extends WithSchemaTree<A, D, E> {
+ private final @NonNull ImmutableMap<QName, SchemaTreeEffectiveStatement<?>> schemaTree;
+ private final @NonNull D declared;
+
+ protected DefaultWithSchemaTree(final D declared, final StmtContext<?, ?, ?> ctx,
+ final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+ this.declared = requireNonNull(declared);
+ this.schemaTree = AbstractSchemaEffectiveDocumentedNode.createSchemaTreeNamespace(
+ ctx.getStatementSourceReference(), substatements);
+ }
+
+ @Override
+ public final D getDeclared() {
+ return declared;
+ }
+
+ @Override
+ protected final ImmutableMap<QName, SchemaTreeEffectiveStatement<?>> schemaTreeNamespace() {
+ return schemaTree;
+ }
+ }
+
+ /**
+ * Stateful version of {@link WithDataTree}. Schema tree and data tree namespaces are eagerly instantiated
+ * (and checked).
+ *
+ * @param <A> Argument type ({@link Void} if statement does not have argument.)
+ * @param <D> Class representing declared version of this statement.
+ * @param <E> Class representing effective version of this statement.
+ */
+ public abstract static class DefaultWithDataTree<A, D extends DeclaredStatement<A>,
+ E extends DataTreeAwareEffectiveStatement<A, D>> extends WithDataTree<A, D, E> {
+ private final @NonNull ImmutableMap<QName, SchemaTreeEffectiveStatement<?>> schemaTree;
+ private final @NonNull ImmutableMap<QName, DataTreeEffectiveStatement<?>> dataTree;
+ private final @NonNull D declared;
+
+ protected DefaultWithDataTree(final D declared, final StmtContext<?, ?, ?> ctx,
+ final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+ this.declared = requireNonNull(declared);
+ final StatementSourceReference ref = ctx.getStatementSourceReference();
+ this.schemaTree = AbstractSchemaEffectiveDocumentedNode.createSchemaTreeNamespace(ref, substatements);
+ this.dataTree = AbstractSchemaEffectiveDocumentedNode.createDataTreeNamespace(ref, schemaTree);
+ }
+
+ @Override
+ public final D getDeclared() {
+ return declared;
+ }
+
+ @Override
+ protected final ImmutableMap<QName, SchemaTreeEffectiveStatement<?>> schemaTreeNamespace() {
+ return schemaTree;
+ }
+
+ @Override
+ protected final ImmutableMap<QName, DataTreeEffectiveStatement<?>> dataTreeNamespace() {
+ return dataTree;
+ }
+ }
}
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.lang.invoke.VarHandle;
+import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
import org.opendaylight.yangtools.yang.model.api.stmt.CaseEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
// EffectiveStatements and SchemaNode interfaces -- which do not overlap completely where child lookups are
// concerned. This ensures that we have SchemaTree index available for use with child lookups.
if (this instanceof SchemaTreeAwareEffectiveStatement || this instanceof DataNodeContainer) {
- final StatementSourceReference ref = ctx.getStatementSourceReference();
- final Map<QName, SchemaTreeEffectiveStatement<?>> schemaChildren = new LinkedHashMap<>();
- streamEffectiveSubstatements(SchemaTreeEffectiveStatement.class).forEach(child -> {
- putChild(schemaChildren, child, ref, "schema");
- });
- schemaTreeNamespace = ImmutableMap.copyOf(schemaChildren);
-
- if (this instanceof DataTreeAwareEffectiveStatement && !schemaTreeNamespace.isEmpty()) {
- final Map<QName, DataTreeEffectiveStatement<?>> dataChildren = new LinkedHashMap<>();
- boolean sameAsSchema = true;
-
- for (SchemaTreeEffectiveStatement<?> child : schemaTreeNamespace.values()) {
- if (child instanceof DataTreeEffectiveStatement) {
- putChild(dataChildren, (DataTreeEffectiveStatement<?>) child, ref, "data");
- } else {
- sameAsSchema = false;
- putChoiceDataChildren(dataChildren, ref, child);
- }
- }
-
- // This is a mighty hack to lower memory usage: if we consumed all schema tree children as data nodes,
- // the two maps are equal and hence we can share the instance.
- dataTreeNamespace = sameAsSchema ? (ImmutableMap) schemaTreeNamespace
- : ImmutableMap.copyOf(dataChildren);
- } else {
- dataTreeNamespace = ImmutableMap.of();
- }
+ schemaTreeNamespace = createSchemaTreeNamespace(ctx.getStatementSourceReference(),
+ effectiveSubstatements());
} else {
- dataTreeNamespace = ImmutableMap.of();
schemaTreeNamespace = ImmutableMap.of();
}
+ if (this instanceof DataTreeAwareEffectiveStatement && !schemaTreeNamespace.isEmpty()) {
+ dataTreeNamespace = createDataTreeNamespace(ctx.getStatementSourceReference(), schemaTreeNamespace);
+ } else {
+ dataTreeNamespace = ImmutableMap.of();
+ }
}
@Override
return child instanceof DataSchemaNode ? Optional.of((DataSchemaNode) child) : Optional.empty();
}
+ static @NonNull ImmutableMap<QName, SchemaTreeEffectiveStatement<?>> createSchemaTreeNamespace(
+ final StatementSourceReference ref, final Collection<? extends EffectiveStatement<?, ?>> substatements) {
+ final Map<QName, SchemaTreeEffectiveStatement<?>> schemaChildren = new LinkedHashMap<>();
+ substatements.stream().filter(SchemaTreeEffectiveStatement.class::isInstance)
+ .forEach(child -> putChild(schemaChildren, (SchemaTreeEffectiveStatement) child, ref, "schema"));
+ return ImmutableMap.copyOf(schemaChildren);
+ }
+
+ static @NonNull ImmutableMap<QName, DataTreeEffectiveStatement<?>> createDataTreeNamespace(
+ final StatementSourceReference ref,
+ final ImmutableMap<QName, SchemaTreeEffectiveStatement<?>> schemaTreeNamespace) {
+ final Map<QName, DataTreeEffectiveStatement<?>> dataChildren = new LinkedHashMap<>();
+ boolean sameAsSchema = true;
+
+ for (SchemaTreeEffectiveStatement<?> child : schemaTreeNamespace.values()) {
+ if (child instanceof DataTreeEffectiveStatement) {
+ putChild(dataChildren, (DataTreeEffectiveStatement<?>) child, ref, "data");
+ } else {
+ sameAsSchema = false;
+ putChoiceDataChildren(dataChildren, ref, child);
+ }
+ }
+
+ // This is a mighty hack to lower memory usage: if we consumed all schema tree children as data nodes,
+ // the two maps are equal and hence we can share the instance.
+ return sameAsSchema ? (ImmutableMap) schemaTreeNamespace : ImmutableMap.copyOf(dataChildren);
+ }
+
@SuppressWarnings("unchecked")
private <T> @NonNull ImmutableSet<T> loadSet(final VarHandle vh, final @NonNull Class<T> clazz) {
final ImmutableSet<T> computed = ImmutableSet.copyOf(allSubstatementsOfType(clazz));
import com.google.common.annotations.Beta;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.opendaylight.yangtools.concepts.Mutable;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
+import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
import org.opendaylight.yangtools.yang.model.api.CopyableNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
import org.opendaylight.yangtools.yang.model.api.MandatoryAware;
import org.opendaylight.yangtools.yang.model.api.MustConstraintAware;
import org.opendaylight.yangtools.yang.model.api.MustDefinition;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer;
import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
import org.opendaylight.yangtools.yang.model.api.WhenConditionAware;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement;
import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
return (Collection<T>) Collections2.filter(effectiveSubstatements(), type::isInstance);
}
+ // FIXME: YANGTOOLS-1068: eliminate this once we can return collections
default <T> List<T> filterEffectiveStatementsList(final Class<T> type) {
- return effectiveSubstatements().stream().filter(type::isInstance).map(type::cast)
- .collect(ImmutableList.toImmutableList());
+ return ImmutableList.copyOf(filterEffectiveStatements(type));
+ }
+
+ // FIXME: YANGTOOLS-1068: eliminate this once we can return collections
+ default <T> Set<T> filterEffectiveStatementsSet(final Class<T> type) {
+ return ImmutableSet.copyOf(filterEffectiveStatements(type));
+ }
+ }
+
+ /**
+ * Bridge between {@link EffectiveStatement} and {@link AugmentationTarget}.
+ *
+ * @param <A> Argument type ({@link Void} if statement does not have argument.)
+ * @param <D> Class representing declared version of this statement.
+ */
+ public interface AugmentationTargetMixin<A, D extends DeclaredStatement<A>>
+ extends Mixin<A, D>, AugmentationTarget {
+ @Override
+ default Set<AugmentationSchemaNode> getAvailableAugmentations() {
+ return filterEffectiveStatementsSet(AugmentationSchemaNode.class);
}
}
}
}
+ /**
+ * Bridge between {@link EffectiveStatementWithFlags} and {@link ActionNodeContainer}.
+ *
+ * @param <A> Argument type ({@link Void} if statement does not have argument.)
+ * @param <D> Class representing declared version of this statement.
+ */
+ public interface ActionNodeContainerMixin<A, D extends DeclaredStatement<A>>
+ extends Mixin<A, D>, ActionNodeContainer {
+ @Override
+ default Set<ActionDefinition> getActions() {
+ return filterEffectiveStatementsSet(ActionDefinition.class);
+ }
+ }
+
+ /**
+ * Bridge between {@link EffectiveStatementWithFlags} and {@link NotificationNodeContainer}.
+ *
+ * @param <A> Argument type ({@link Void} if statement does not have argument.)
+ * @param <D> Class representing declared version of this statement.
+ */
+ public interface NotificationNodeContainerMixin<A, D extends DeclaredStatement<A>>
+ extends Mixin<A, D>, NotificationNodeContainer {
+ @Override
+ default Set<NotificationDefinition> getNotifications() {
+ return filterEffectiveStatementsSet(NotificationDefinition.class);
+ }
+ }
+
/**
* Bridge between {@link EffectiveStatementWithFlags} and {@link MustConstraintAware}.
*
}
}
+ /**
+ * Bridge between {@link EffectiveStatementWithFlags} and {@link DataNodeContainer}.
+ *
+ * @param <A> Argument type ({@link Void} if statement does not have argument.)
+ * @param <D> Class representing declared version of this statement.
+ */
+ public interface DataNodeContainerMixin<A, D extends DeclaredStatement<A>> extends DataNodeContainer, Mixin<A, D> {
+ @Override
+ default Set<TypeDefinition<?>> getTypeDefinitions() {
+ // TODO: the cast here is needed to work around Java 11 javac type inference issue
+ return (Set) effectiveSubstatements().stream().filter(TypedefEffectiveStatement.class::isInstance)
+ .map(stmt -> ((TypedefEffectiveStatement) stmt).getTypeDefinition())
+ .collect(ImmutableSet.toImmutableSet());
+ }
+
+ @Override
+ default Collection<DataSchemaNode> getChildNodes() {
+ return filterEffectiveStatements(DataSchemaNode.class);
+ }
+
+ @Override
+ default Set<GroupingDefinition> getGroupings() {
+ return filterEffectiveStatementsSet(GroupingDefinition.class);
+ }
+
+ @Override
+ default Set<UsesNode> getUses() {
+ return filterEffectiveStatementsSet(UsesNode.class);
+ }
+ }
+
/**
* Bridge between {@link EffectiveStatementWithFlags} and {@link DataSchemaNode}.
*
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
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.HashSet;
import java.util.Iterator;
import java.util.Optional;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.YangVersion;
import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.MaxElementsEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.MinElementsEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
}
return false;
}
+
+ public static void checkUniqueGroupings(final StmtContext<?, ?, ?> ctx,
+ final Collection<? extends EffectiveStatement<?, ?>> statements) {
+ checkUniqueNodes(ctx, statements, GroupingDefinition.class);
+ }
+
+ public static void checkUniqueTypedefs(final StmtContext<?, ?, ?> ctx,
+ final Collection<? extends EffectiveStatement<?, ?>> statements) {
+ final Set<Object> typedefs = new HashSet<>();
+ for (EffectiveStatement<?, ?> stmt : statements) {
+ if (stmt instanceof TypedefEffectiveStatement
+ && !typedefs.add(((TypedefEffectiveStatement) stmt).getTypeDefinition())) {
+ throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, stmt);
+ }
+ }
+ }
+
+ public static void checkUniqueUses(final StmtContext<?, ?, ?> ctx,
+ final Collection<? extends EffectiveStatement<?, ?>> statements) {
+ checkUniqueNodes(ctx, statements, UsesNode.class);
+ }
+
+ private static void checkUniqueNodes(final StmtContext<?, ?, ?> ctx,
+ final Collection<? extends EffectiveStatement<?, ?>> statements, final Class<?> type) {
+ final Set<Object> nodes = new HashSet<>();
+ for (EffectiveStatement<?, ?> stmt : statements) {
+ if (type.isInstance(stmt) && !nodes.add(stmt)) {
+ throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, stmt);
+ }
+ }
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.list;
+
+import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.UniqueConstraint;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ListEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ListStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.compat.ActionNodeContainerCompat;
+import org.opendaylight.yangtools.yang.model.api.stmt.compat.NotificationNodeContainerCompat;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredEffectiveStatement.DefaultWithDataTree;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.ActionNodeContainerMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.AugmentationTargetMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.DataNodeContainerMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.DataSchemaNodeMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.MustConstraintMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.NotificationNodeContainerMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.UserOrderedMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.WhenConditionMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStmtUtils;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+
+abstract class AbstractListEffectiveStatement
+ extends DefaultWithDataTree<QName, ListStatement, ListEffectiveStatement>
+ implements ListEffectiveStatement, ListSchemaNode, DerivableSchemaNode,
+ ActionNodeContainerCompat<QName, ListStatement>, NotificationNodeContainerCompat<QName, ListStatement>,
+ DataSchemaNodeMixin<QName, ListStatement>, UserOrderedMixin<QName, ListStatement>,
+ DataNodeContainerMixin<QName, ListStatement>, WhenConditionMixin<QName, ListStatement>,
+ AugmentationTargetMixin<QName, ListStatement>, NotificationNodeContainerMixin<QName, ListStatement>,
+ ActionNodeContainerMixin<QName, ListStatement>, MustConstraintMixin<QName, ListStatement> {
+ private final int flags;
+ // Variable: either a single substatement or an ImmutableList
+ private final @NonNull Object substatements;
+ private final @NonNull SchemaPath path;
+ // Variable: either a single QName or an ImmutableList
+ private final @NonNull Object keyDefinition;
+
+ AbstractListEffectiveStatement(final ListStatement declared, final SchemaPath path, final int flags,
+ final StmtContext<?, ?, ?> ctx, final ImmutableList<? extends EffectiveStatement<?, ?>> substatements,
+ final ImmutableList<QName> keyDefinition) {
+ super(declared, ctx, substatements);
+
+ EffectiveStmtUtils.checkUniqueGroupings(ctx, substatements);
+ EffectiveStmtUtils.checkUniqueTypedefs(ctx, substatements);
+ EffectiveStmtUtils.checkUniqueUses(ctx, substatements);
+
+ this.substatements = substatements.size() == 1 ? substatements.get(0) : substatements;
+ this.path = requireNonNull(path);
+ this.keyDefinition = keyDefinition.size() == 1 ? keyDefinition.get(0) : keyDefinition;
+ this.flags = flags;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ public final ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
+ return (ImmutableList) listFrom(substatements, EffectiveStatement.class);
+ }
+
+ @Override
+ public final int flags() {
+ return flags;
+ }
+
+ @Override
+ public final @NonNull QName argument() {
+ return getQName();
+ }
+
+ @Override
+ public final SchemaPath getPath() {
+ return path;
+ }
+
+ @Override
+ public final boolean isUserOrdered() {
+ return userOrdered();
+ }
+
+ @Override
+ public final List<QName> getKeyDefinition() {
+ return listFrom(keyDefinition, QName.class);
+ }
+
+ @Override
+ public final Optional<DataSchemaNode> findDataChildByName(final QName name) {
+ return findDataSchemaNode(name);
+ }
+
+ @Override
+ public final Collection<UniqueConstraint> getUniqueConstraints() {
+ return effectiveSubstatements().stream()
+ .filter(UniqueConstraint.class::isInstance)
+ .map(UniqueConstraint.class::cast)
+ .collect(ImmutableList.toImmutableList());
+ }
+
+ @Override
+ public final int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Objects.hashCode(getQName());
+ result = prime * result + Objects.hashCode(getPath());
+ return result;
+ }
+
+ @Override
+ public final boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof AbstractListEffectiveStatement)) {
+ return false;
+ }
+ final AbstractListEffectiveStatement other = (AbstractListEffectiveStatement) obj;
+ return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath());
+ }
+
+ @Override
+ public final String toString() {
+ return "list " + getQName().getLocalName();
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> @NonNull ImmutableList<T> listFrom(final Object obj, final Class<T> type) {
+ if (obj instanceof ImmutableList) {
+ return (ImmutableList<T>) obj;
+ }
+ verify(type.isInstance(obj), "Unexpected list value %s", obj);
+ return ImmutableList.of(type.cast(obj));
+ }
+}
*/
package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.list;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.KeyEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ListEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ListStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.OrderedByEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
+import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace;
-import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseQNameStatementSupport;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.EffectiveStatementWithFlags.FlagsBuilder;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStmtUtils;
+import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-abstract class AbstractListStatementSupport
- extends AbstractQNameStatementSupport<ListStatement, EffectiveStatement<QName, ListStatement>> {
+abstract class AbstractListStatementSupport extends BaseQNameStatementSupport<ListStatement, ListEffectiveStatement> {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractListStatementSupport.class);
AbstractListStatementSupport() {
super(YangStmtMapping.LIST);
}
@Override
- public final void onStatementAdded(
- final Mutable<QName, ListStatement, EffectiveStatement<QName, ListStatement>> stmt) {
+ public final void onStatementAdded(final Mutable<QName, ListStatement, ListEffectiveStatement> stmt) {
stmt.coerceParentContext().addToNs(ChildSchemaNodeNamespace.class, stmt.coerceStatementArgument(), stmt);
}
}
@Override
- public final EffectiveStatement<QName, ListStatement> createEffective(
- final StmtContext<QName, ListStatement, EffectiveStatement<QName, ListStatement>> ctx) {
- return new ListEffectiveStatementImpl(ctx);
+ protected final ListEffectiveStatement createEffective(
+ final StmtContext<QName, ListStatement, ListEffectiveStatement> ctx,
+ final ListStatement declared, final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+ final StatementSourceReference ref = ctx.getStatementSourceReference();
+ final SchemaPath path = ctx.getSchemaPath().get();
+ final ListSchemaNode original = (ListSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective)
+ .orElse(null);
+
+ final ImmutableList<QName> keyDefinition;
+ final KeyEffectiveStatement keyStmt = findFirstStatement(substatements, KeyEffectiveStatement.class);
+ if (keyStmt != null) {
+ final List<QName> keyDefinitionInit = new ArrayList<>(keyStmt.argument().size());
+ final Set<QName> possibleLeafQNamesForKey = new HashSet<>();
+ for (final EffectiveStatement<?, ?> effectiveStatement : substatements) {
+ if (effectiveStatement instanceof LeafSchemaNode) {
+ possibleLeafQNamesForKey.add(((LeafSchemaNode) effectiveStatement).getQName());
+ }
+ }
+ for (final SchemaNodeIdentifier key : keyStmt.argument()) {
+ final QName keyQName = key.getLastComponent();
+
+ if (!possibleLeafQNamesForKey.contains(keyQName)) {
+ throw new InferenceException(ref, "Key '%s' misses node '%s' in list '%s'",
+ keyStmt.getDeclared().rawArgument(), keyQName.getLocalName(), ctx.getStatementArgument());
+ }
+ keyDefinitionInit.add(keyQName);
+ }
+
+ keyDefinition = ImmutableList.copyOf(keyDefinitionInit);
+ } else {
+ keyDefinition = ImmutableList.of();
+ }
+
+ final boolean configuration = ctx.isConfiguration();
+ final int flags = new FlagsBuilder()
+ .setHistory(ctx.getCopyHistory())
+ .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT))
+ .setConfiguration(configuration)
+ .setUserOrdered(findFirstArgument(substatements, OrderedByEffectiveStatement.class, "system")
+ .equals("user"))
+ .toFlags();
+ if (configuration && keyDefinition.isEmpty()) {
+ LOG.info("Configuration list {} does not define any keys in violation of RFC7950 section 7.8.2. While "
+ + " this is fine with OpenDaylight, it can cause interoperability issues with other systems "
+ + "[at {}]", ctx.getStatementArgument(), ref);
+ }
+
+ final Optional<ElementCountConstraint> elementCountConstraint =
+ EffectiveStmtUtils.createElementCountConstraint(substatements);
+ return original == null && !elementCountConstraint.isPresent()
+ ? new EmptyListEffectiveStatement(declared, path, flags, ctx, substatements, keyDefinition)
+ : new RegularListEffectiveStatement(declared, path, flags, ctx, substatements, keyDefinition,
+ elementCountConstraint.orElse(null), original);
+ }
+
+ @Override
+ protected final ListEffectiveStatement createEmptyEffective(
+ final StmtContext<QName, ListStatement, ListEffectiveStatement> ctx, final ListStatement declared) {
+ return createEffective(ctx, declared, ImmutableList.of());
}
-}
\ No newline at end of file
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.list;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ListStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+
+final class EmptyListEffectiveStatement extends AbstractListEffectiveStatement {
+ EmptyListEffectiveStatement(final ListStatement declared, final SchemaPath path, final int flags,
+ final StmtContext<?, ?, ?> ctx, final ImmutableList<? extends EffectiveStatement<?, ?>> substatements,
+ final ImmutableList<QName> keyDefinition) {
+ super(declared, path, flags, ctx, substatements, keyDefinition);
+ }
+
+ @Override
+ public Optional<? extends SchemaNode> getOriginal() {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<ElementCountConstraint> getElementCountConstraint() {
+ return Optional.empty();
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.list;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSet.Builder;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
-import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
-import org.opendaylight.yangtools.yang.model.api.UniqueConstraint;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.KeyEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.ListEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.ListStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.OrderedByEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
-import org.opendaylight.yangtools.yang.model.api.stmt.compat.ActionNodeContainerCompat;
-import org.opendaylight.yangtools.yang.model.api.stmt.compat.NotificationNodeContainerCompat;
-import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveMustConstraintAwareSimpleDataNodeContainer;
-import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStmtUtils;
-import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
-import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-final class ListEffectiveStatementImpl
- extends AbstractEffectiveMustConstraintAwareSimpleDataNodeContainer<ListStatement>
- implements ListEffectiveStatement, ListSchemaNode, DerivableSchemaNode,
- ActionNodeContainerCompat<QName, ListStatement>, NotificationNodeContainerCompat<QName, ListStatement> {
- private static final Logger LOG = LoggerFactory.getLogger(ListEffectiveStatementImpl.class);
- private static final String ORDER_BY_USER_KEYWORD = "user";
-
- private final boolean userOrdered;
- private final ImmutableList<QName> keyDefinition;
- private final ListSchemaNode original;
- private final @NonNull ImmutableSet<ActionDefinition> actions;
- private final @NonNull ImmutableSet<NotificationDefinition> notifications;
- private final @NonNull ImmutableList<UniqueConstraint> uniqueConstraints;
- private final ElementCountConstraint elementCountConstraint;
-
- ListEffectiveStatementImpl(
- final StmtContext<QName, ListStatement, EffectiveStatement<QName, ListStatement>> ctx) {
- super(ctx);
-
- this.original = (ListSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective).orElse(null);
- this.userOrdered = findFirstEffectiveSubstatementArgument(OrderedByEffectiveStatement.class)
- .map(ORDER_BY_USER_KEYWORD::equals).orElse(Boolean.FALSE).booleanValue();
-
- // initKeyDefinition
- final Optional<KeyEffectiveStatement> optKeyStmt = findFirstEffectiveSubstatement(KeyEffectiveStatement.class);
- if (optKeyStmt.isPresent()) {
- final KeyEffectiveStatement keyStmt = optKeyStmt.get();
- final List<QName> keyDefinitionInit = new ArrayList<>(keyStmt.argument().size());
- final Set<QName> possibleLeafQNamesForKey = new HashSet<>();
- for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
- if (effectiveStatement instanceof LeafSchemaNode) {
- possibleLeafQNamesForKey.add(((LeafSchemaNode) effectiveStatement).getQName());
- }
- }
- for (final SchemaNodeIdentifier key : keyStmt.argument()) {
- final QName keyQName = key.getLastComponent();
-
- if (!possibleLeafQNamesForKey.contains(keyQName)) {
- throw new InferenceException(ctx.getStatementSourceReference(),
- "Key '%s' misses node '%s' in list '%s'", keyStmt.getDeclared().rawArgument(),
- keyQName.getLocalName(), ctx.getStatementArgument());
- }
- keyDefinitionInit.add(keyQName);
- }
-
- this.keyDefinition = ImmutableList.copyOf(keyDefinitionInit);
- } else {
- this.keyDefinition = ImmutableList.of();
- }
-
- if (isConfiguration() && keyDefinition.isEmpty()) {
- LOG.info("Configuration list {} does not define any keys in violation of RFC7950 section 7.8.2. While "
- + " this is fine with OpenDaylight, it can cause interoperability issues with other systems "
- + "[at {}]", ctx.getStatementArgument(), ctx.getStatementSourceReference());
- }
-
- this.uniqueConstraints = ImmutableList.copyOf(allSubstatementsOfType(UniqueConstraint.class));
-
- final Builder<ActionDefinition> actionsBuilder = ImmutableSet.builder();
- final Builder<NotificationDefinition> notificationsBuilder = ImmutableSet.builder();
- for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
- if (effectiveStatement instanceof ActionDefinition) {
- actionsBuilder.add((ActionDefinition) effectiveStatement);
- }
-
- if (effectiveStatement instanceof NotificationDefinition) {
- notificationsBuilder.add((NotificationDefinition) effectiveStatement);
- }
- }
-
- this.actions = actionsBuilder.build();
- this.notifications = notificationsBuilder.build();
- elementCountConstraint = EffectiveStmtUtils.createElementCountConstraint(this).orElse(null);
- }
-
- @Override
- public Optional<ListSchemaNode> getOriginal() {
- return Optional.ofNullable(original);
- }
-
- @Override
- public List<QName> getKeyDefinition() {
- return keyDefinition;
- }
-
- @Override
- public Set<ActionDefinition> getActions() {
- return actions;
- }
-
- @Override
- public Set<NotificationDefinition> getNotifications() {
- return notifications;
- }
-
- @Override
- public Collection<UniqueConstraint> getUniqueConstraints() {
- return uniqueConstraints;
- }
-
- @Override
- public boolean isUserOrdered() {
- return userOrdered;
- }
-
- @Override
- public Optional<ElementCountConstraint> getElementCountConstraint() {
- return Optional.ofNullable(elementCountConstraint);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + Objects.hashCode(getQName());
- result = prime * result + Objects.hashCode(getPath());
- return result;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final ListEffectiveStatementImpl other = (ListEffectiveStatementImpl) obj;
- return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath());
- }
-
- @Override
- public String toString() {
- return "list " + getQName().getLocalName();
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.list;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ListStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+
+final class RegularListEffectiveStatement extends AbstractListEffectiveStatement {
+ private final ElementCountConstraint elementCountConstraint;
+ private final ListSchemaNode original;
+
+ RegularListEffectiveStatement(final ListStatement declared, final SchemaPath path, final int flags,
+ final StmtContext<?, ?, ?> ctx, final ImmutableList<? extends EffectiveStatement<?, ?>> substatements,
+ final ImmutableList<QName> keyDefinition, final ElementCountConstraint elementCountConstraint,
+ final ListSchemaNode original) {
+ super(declared, path, flags, ctx, substatements, keyDefinition);
+ this.elementCountConstraint = elementCountConstraint;
+ this.original = original;
+ }
+
+ @Override
+ public Optional<ListSchemaNode> getOriginal() {
+ return Optional.ofNullable(original);
+ }
+
+ @Override
+ public Optional<ElementCountConstraint> getElementCountConstraint() {
+ return Optional.ofNullable(elementCountConstraint);
+ }
+}