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.YangVersion;
20 import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
21 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
22 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.UsesNode;
24 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
25 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.MaxElementsEffectiveStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.MinElementsEffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
29 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
30 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
31 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
33 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx;
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 EffectiveStmtCtx.Current<?, ?> stmt,
47 final EffectiveStatement<?, ?> effectiveStatement) {
48 return new SourceException(stmt,
49 "Error in module '%s': cannot add '%s'. Node name collision: '%s' already declared.",
50 stmt.moduleName().getLocalName(), effectiveStatement.argument(), effectiveStatement.argument());
53 public static Optional<ElementCountConstraint> createElementCountConstraint(final EffectiveStatement<?, ?> stmt) {
54 return createElementCountConstraint(
55 stmt.findFirstEffectiveSubstatementArgument(MinElementsEffectiveStatement.class).orElse(null),
56 stmt.findFirstEffectiveSubstatementArgument(MaxElementsEffectiveStatement.class).orElse(null));
59 public static Optional<ElementCountConstraint> createElementCountConstraint(
60 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
61 return createElementCountConstraint(
62 AbstractStatementSupport.findFirstArgument(substatements, MinElementsEffectiveStatement.class, null),
63 AbstractStatementSupport.findFirstArgument(substatements, MaxElementsEffectiveStatement.class, null));
66 private static Optional<ElementCountConstraint> createElementCountConstraint(
67 final @Nullable Integer min, final @Nullable String max) {
68 final Integer minElements;
70 minElements = min > 0 ? min : null;
75 final Integer maxElements;
76 if (max != null && !UNBOUNDED_STR.equals(max)) {
77 final Integer m = Integer.valueOf(max);
78 maxElements = m < Integer.MAX_VALUE ? m : null;
83 return ElementCountConstraint.forNullable(minElements, maxElements);
87 * Checks whether supplied type has any of specified default values marked
88 * with an if-feature. This method creates mutable copy of supplied set of
94 * type statement which should be checked
95 * @param defaultValues
96 * set of default values which should be checked. The method
97 * creates mutable copy of this set
99 * @return true if any of specified default values is marked with an
100 * if-feature, otherwise false
102 public static boolean hasDefaultValueMarkedWithIfFeature(final YangVersion yangVersion,
103 final TypeEffectiveStatement<?> typeStmt, final Set<String> defaultValues) {
104 return !defaultValues.isEmpty() && yangVersion == YangVersion.VERSION_1_1
105 && isRelevantForIfFeatureCheck(typeStmt)
106 && isAnyDefaultValueMarkedWithIfFeature(typeStmt, new HashSet<>(defaultValues));
110 * Checks whether supplied type has specified default value marked with an
111 * if-feature. This method creates mutable set of supplied default value.
116 * type statement which should be checked
117 * @param defaultValue
118 * default value to be checked
120 * @return true if specified default value is marked with an if-feature,
123 public static boolean hasDefaultValueMarkedWithIfFeature(final YangVersion yangVersion,
124 final TypeEffectiveStatement<?> typeStmt, final String defaultValue) {
125 final HashSet<String> defaultValues = new HashSet<>();
126 defaultValues.add(defaultValue);
127 return !Strings.isNullOrEmpty(defaultValue) && yangVersion == YangVersion.VERSION_1_1
128 && isRelevantForIfFeatureCheck(typeStmt)
129 && isAnyDefaultValueMarkedWithIfFeature(typeStmt, defaultValues);
132 private static boolean isRelevantForIfFeatureCheck(final TypeEffectiveStatement<?> typeStmt) {
133 final TypeDefinition<?> typeDefinition = typeStmt.getTypeDefinition();
134 return typeDefinition instanceof EnumTypeDefinition || typeDefinition instanceof BitsTypeDefinition
135 || typeDefinition instanceof UnionTypeDefinition;
138 private static boolean isAnyDefaultValueMarkedWithIfFeature(final TypeEffectiveStatement<?> typeStmt,
139 final Set<String> defaultValues) {
140 final Iterator<? extends EffectiveStatement<?, ?>> iter = typeStmt.effectiveSubstatements().iterator();
141 while (iter.hasNext() && !defaultValues.isEmpty()) {
142 final EffectiveStatement<?, ?> effectiveSubstatement = iter.next();
143 if (YangStmtMapping.BIT.equals(effectiveSubstatement.statementDefinition())) {
144 final String bitName = (String) effectiveSubstatement.argument();
145 if (defaultValues.remove(bitName) && containsIfFeature(effectiveSubstatement)) {
148 } else if (YangStmtMapping.ENUM.equals(effectiveSubstatement.statementDefinition())
149 && defaultValues.remove(effectiveSubstatement.argument())
150 && containsIfFeature(effectiveSubstatement)) {
152 } else if (effectiveSubstatement instanceof TypeEffectiveStatement && isAnyDefaultValueMarkedWithIfFeature(
153 (TypeEffectiveStatement<?>) effectiveSubstatement, defaultValues)) {
161 private static boolean containsIfFeature(final EffectiveStatement<?, ?> effectiveStatement) {
162 for (final EffectiveStatement<?, ?> effectiveSubstatement : effectiveStatement.effectiveSubstatements()) {
163 if (YangStmtMapping.IF_FEATURE.equals(effectiveSubstatement.statementDefinition())) {
170 public static void checkUniqueGroupings(final EffectiveStmtCtx.Current<?, ?> stmt,
171 final Collection<? extends EffectiveStatement<?, ?>> statements) {
172 checkUniqueNodes(stmt, statements, GroupingDefinition.class);
175 public static void checkUniqueTypedefs(final EffectiveStmtCtx.Current<?, ?> stmt,
176 final Collection<? extends EffectiveStatement<?, ?>> statements) {
177 final Set<Object> typedefs = new HashSet<>();
178 for (EffectiveStatement<?, ?> statement : statements) {
179 if (statement instanceof TypedefEffectiveStatement
180 && !typedefs.add(((TypedefEffectiveStatement) statement).getTypeDefinition())) {
181 throw EffectiveStmtUtils.createNameCollisionSourceException(stmt, statement);
186 public static void checkUniqueUses(final EffectiveStmtCtx.Current<?, ?> stmt,
187 final Collection<? extends EffectiveStatement<?, ?>> statements) {
188 checkUniqueNodes(stmt, statements, UsesNode.class);
191 private static void checkUniqueNodes(final EffectiveStmtCtx.Current<?, ?> stmt,
192 final Collection<? extends EffectiveStatement<?, ?>> statements, final Class<?> type) {
193 final Set<Object> nodes = new HashSet<>();
194 for (EffectiveStatement<?, ?> statement : statements) {
195 if (type.isInstance(statement) && !nodes.add(statement)) {
196 throw EffectiveStmtUtils.createNameCollisionSourceException(stmt, statement);