2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Strings;
12 import com.google.common.collect.ImmutableList;
13 import java.util.Collection;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.Optional;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.common.YangVersion;
21 import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
22 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
23 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.UsesNode;
25 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
26 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.MaxElementsEffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.MinElementsEffectiveStatement;
29 import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
30 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
31 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
33 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
35 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
38 public final class EffectiveStmtUtils {
39 // FIXME: this should reside somewhere in max_elements
40 private static final String UNBOUNDED_STR = "unbounded";
42 private EffectiveStmtUtils() {
46 public static SourceException createNameCollisionSourceException(final StmtContext<?, ?, ?> ctx,
47 final EffectiveStatement<?, ?> effectiveStatement) {
48 return new SourceException(ctx.getStatementSourceReference(),
49 "Error in module '%s': cannot add '%s'. Node name collision: '%s' already declared.",
50 ctx.getRoot().getStatementArgument(),
51 effectiveStatement.argument(),
52 effectiveStatement.argument());
55 public static Optional<ElementCountConstraint> createElementCountConstraint(final EffectiveStatement<?, ?> stmt) {
56 return createElementCountConstraint(
57 stmt.findFirstEffectiveSubstatementArgument(MinElementsEffectiveStatement.class).orElse(null),
58 stmt.findFirstEffectiveSubstatementArgument(MaxElementsEffectiveStatement.class).orElse(null));
61 public static Optional<ElementCountConstraint> createElementCountConstraint(
62 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
63 return createElementCountConstraint(
64 BaseQNameStatementSupport.findFirstArgument(substatements, MinElementsEffectiveStatement.class, null),
65 BaseQNameStatementSupport.findFirstArgument(substatements, MaxElementsEffectiveStatement.class, null));
68 private static Optional<ElementCountConstraint> createElementCountConstraint(
69 final @Nullable Integer min, final @Nullable String max) {
70 final Integer minElements;
72 minElements = min > 0 ? min : null;
77 final Integer maxElements;
78 if (max != null && !UNBOUNDED_STR.equals(max)) {
79 final Integer m = Integer.valueOf(max);
80 maxElements = m < Integer.MAX_VALUE ? m : null;
85 return ElementCountConstraint.forNullable(minElements, maxElements);
89 * Checks whether supplied type has any of specified default values marked
90 * with an if-feature. This method creates mutable copy of supplied set of
96 * type statement which should be checked
97 * @param defaultValues
98 * set of default values which should be checked. The method
99 * creates mutable copy of this set
101 * @return true if any of specified default values is marked with an
102 * if-feature, otherwise false
104 public static boolean hasDefaultValueMarkedWithIfFeature(final YangVersion yangVersion,
105 final TypeEffectiveStatement<?> typeStmt, final Set<String> defaultValues) {
106 return !defaultValues.isEmpty() && yangVersion == YangVersion.VERSION_1_1
107 && isRelevantForIfFeatureCheck(typeStmt)
108 && isAnyDefaultValueMarkedWithIfFeature(typeStmt, new HashSet<>(defaultValues));
112 * Checks whether supplied type has specified default value marked with an
113 * if-feature. This method creates mutable set of supplied default value.
118 * type statement which should be checked
119 * @param defaultValue
120 * default value to be checked
122 * @return true if specified default value is marked with an if-feature,
125 public static boolean hasDefaultValueMarkedWithIfFeature(final YangVersion yangVersion,
126 final TypeEffectiveStatement<?> typeStmt, final String defaultValue) {
127 final HashSet<String> defaultValues = new HashSet<>();
128 defaultValues.add(defaultValue);
129 return !Strings.isNullOrEmpty(defaultValue) && yangVersion == YangVersion.VERSION_1_1
130 && isRelevantForIfFeatureCheck(typeStmt)
131 && isAnyDefaultValueMarkedWithIfFeature(typeStmt, defaultValues);
134 private static boolean isRelevantForIfFeatureCheck(final TypeEffectiveStatement<?> typeStmt) {
135 final TypeDefinition<?> typeDefinition = typeStmt.getTypeDefinition();
136 return typeDefinition instanceof EnumTypeDefinition || typeDefinition instanceof BitsTypeDefinition
137 || typeDefinition instanceof UnionTypeDefinition;
140 private static boolean isAnyDefaultValueMarkedWithIfFeature(final TypeEffectiveStatement<?> typeStmt,
141 final Set<String> defaultValues) {
142 final Iterator<? extends EffectiveStatement<?, ?>> iter = typeStmt.effectiveSubstatements().iterator();
143 while (iter.hasNext() && !defaultValues.isEmpty()) {
144 final EffectiveStatement<?, ?> effectiveSubstatement = iter.next();
145 if (YangStmtMapping.BIT.equals(effectiveSubstatement.statementDefinition())) {
146 final QName bitQName = (QName) effectiveSubstatement.argument();
147 if (defaultValues.remove(bitQName.getLocalName()) && containsIfFeature(effectiveSubstatement)) {
150 } else if (YangStmtMapping.ENUM.equals(effectiveSubstatement.statementDefinition())
151 && defaultValues.remove(effectiveSubstatement.argument())
152 && containsIfFeature(effectiveSubstatement)) {
154 } else if (effectiveSubstatement instanceof TypeEffectiveStatement && isAnyDefaultValueMarkedWithIfFeature(
155 (TypeEffectiveStatement<?>) effectiveSubstatement, defaultValues)) {
163 private static boolean containsIfFeature(final EffectiveStatement<?, ?> effectiveStatement) {
164 for (final EffectiveStatement<?, ?> effectiveSubstatement : effectiveStatement.effectiveSubstatements()) {
165 if (YangStmtMapping.IF_FEATURE.equals(effectiveSubstatement.statementDefinition())) {
172 public static void checkUniqueGroupings(final StmtContext<?, ?, ?> ctx,
173 final Collection<? extends EffectiveStatement<?, ?>> statements) {
174 checkUniqueNodes(ctx, statements, GroupingDefinition.class);
177 public static void checkUniqueTypedefs(final StmtContext<?, ?, ?> ctx,
178 final Collection<? extends EffectiveStatement<?, ?>> statements) {
179 final Set<Object> typedefs = new HashSet<>();
180 for (EffectiveStatement<?, ?> stmt : statements) {
181 if (stmt instanceof TypedefEffectiveStatement
182 && !typedefs.add(((TypedefEffectiveStatement) stmt).getTypeDefinition())) {
183 throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, stmt);
188 public static void checkUniqueUses(final StmtContext<?, ?, ?> ctx,
189 final Collection<? extends EffectiveStatement<?, ?>> statements) {
190 checkUniqueNodes(ctx, statements, UsesNode.class);
193 private static void checkUniqueNodes(final StmtContext<?, ?, ?> ctx,
194 final Collection<? extends EffectiveStatement<?, ?>> statements, final Class<?> type) {
195 final Set<Object> nodes = new HashSet<>();
196 for (EffectiveStatement<?, ?> stmt : statements) {
197 if (type.isInstance(stmt) && !nodes.add(stmt)) {
198 throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, stmt);