Refactor Leaf(List)EffectiveStatementImpl
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / EffectiveStmtUtils.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
10
11 import com.google.common.annotations.Beta;
12 import com.google.common.base.Strings;
13 import com.google.common.collect.ImmutableList;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.Optional;
17 import java.util.Set;
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.TypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
24 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.MaxElementsEffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.MinElementsEffectiveStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
30 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
31 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
32 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
33
34 @Beta
35 public final class EffectiveStmtUtils {
36     // FIXME: this should reside somewhere in max_elements
37     private static final String UNBOUNDED_STR = "unbounded";
38
39     private EffectiveStmtUtils() {
40         // Hidden on purpose
41     }
42
43     public static SourceException createNameCollisionSourceException(final StmtContext<?, ?, ?> ctx,
44             final EffectiveStatement<?, ?> effectiveStatement) {
45         return new SourceException(ctx.getStatementSourceReference(),
46             "Error in module '%s': cannot add '%s'. Node name collision: '%s' already declared.",
47             ctx.getRoot().getStatementArgument(),
48             effectiveStatement.argument(),
49             effectiveStatement.argument());
50     }
51
52     public static Optional<ElementCountConstraint> createElementCountConstraint(final EffectiveStatement<?, ?> stmt) {
53         return createElementCountConstraint(
54             stmt.findFirstEffectiveSubstatementArgument(MinElementsEffectiveStatement.class).orElse(null),
55             stmt.findFirstEffectiveSubstatementArgument(MaxElementsEffectiveStatement.class).orElse(null));
56     }
57
58     public static Optional<ElementCountConstraint> createElementCountConstraint(
59             final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
60         return createElementCountConstraint(
61             BaseQNameStatementSupport.findFirstArgument(substatements, MinElementsEffectiveStatement.class, null),
62             BaseQNameStatementSupport.findFirstArgument(substatements, MaxElementsEffectiveStatement.class, null));
63     }
64
65     private static Optional<ElementCountConstraint> createElementCountConstraint(
66             final @Nullable Integer min, final @Nullable String max) {
67         final Integer minElements;
68         if (min != null) {
69             minElements = min > 0 ? min : null;
70         } else {
71             minElements = null;
72         }
73
74         final Integer maxElements;
75         if (max != null && !UNBOUNDED_STR.equals(max)) {
76             final Integer m = Integer.valueOf(max);
77             maxElements = m < Integer.MAX_VALUE ? m : null;
78         } else {
79             maxElements = null;
80         }
81
82         return ElementCountConstraint.forNullable(minElements, maxElements);
83     }
84
85     /**
86      * Checks whether supplied type has any of specified default values marked
87      * with an if-feature. This method creates mutable copy of supplied set of
88      * default values.
89      *
90      * @param yangVersion
91      *            yang version
92      * @param typeStmt
93      *            type statement which should be checked
94      * @param defaultValues
95      *            set of default values which should be checked. The method
96      *            creates mutable copy of this set
97      *
98      * @return true if any of specified default values is marked with an
99      *         if-feature, otherwise false
100      */
101     public static boolean hasDefaultValueMarkedWithIfFeature(final YangVersion yangVersion,
102             final TypeEffectiveStatement<?> typeStmt, final Set<String> defaultValues) {
103         return !defaultValues.isEmpty() && yangVersion == YangVersion.VERSION_1_1
104                 && isRelevantForIfFeatureCheck(typeStmt)
105                 && isAnyDefaultValueMarkedWithIfFeature(typeStmt, new HashSet<>(defaultValues));
106     }
107
108     /**
109      * Checks whether supplied type has specified default value marked with an
110      * if-feature. This method creates mutable set of supplied default value.
111      *
112      * @param yangVersion
113      *            yang version
114      * @param typeStmt
115      *            type statement which should be checked
116      * @param defaultValue
117      *            default value to be checked
118      *
119      * @return true if specified default value is marked with an if-feature,
120      *         otherwise false
121      */
122     public static boolean hasDefaultValueMarkedWithIfFeature(final YangVersion yangVersion,
123             final TypeEffectiveStatement<?> typeStmt, final String defaultValue) {
124         final HashSet<String> defaultValues = new HashSet<>();
125         defaultValues.add(defaultValue);
126         return !Strings.isNullOrEmpty(defaultValue) && yangVersion == YangVersion.VERSION_1_1
127                 && isRelevantForIfFeatureCheck(typeStmt)
128                 && isAnyDefaultValueMarkedWithIfFeature(typeStmt, defaultValues);
129     }
130
131     private static boolean isRelevantForIfFeatureCheck(final TypeEffectiveStatement<?> typeStmt) {
132         final TypeDefinition<?> typeDefinition = typeStmt.getTypeDefinition();
133         return typeDefinition instanceof EnumTypeDefinition || typeDefinition instanceof BitsTypeDefinition
134                 || typeDefinition instanceof UnionTypeDefinition;
135     }
136
137     private static boolean isAnyDefaultValueMarkedWithIfFeature(final TypeEffectiveStatement<?> typeStmt,
138             final Set<String> defaultValues) {
139         final Iterator<? extends EffectiveStatement<?, ?>> iter = typeStmt.effectiveSubstatements().iterator();
140         while (iter.hasNext() && !defaultValues.isEmpty()) {
141             final EffectiveStatement<?, ?> effectiveSubstatement = iter.next();
142             if (YangStmtMapping.BIT.equals(effectiveSubstatement.statementDefinition())) {
143                 final QName bitQName = (QName) effectiveSubstatement.argument();
144                 if (defaultValues.remove(bitQName.getLocalName()) && containsIfFeature(effectiveSubstatement)) {
145                     return true;
146                 }
147             } else if (YangStmtMapping.ENUM.equals(effectiveSubstatement.statementDefinition())
148                     && defaultValues.remove(effectiveSubstatement.argument())
149                     && containsIfFeature(effectiveSubstatement)) {
150                 return true;
151             } else if (effectiveSubstatement instanceof TypeEffectiveStatement && isAnyDefaultValueMarkedWithIfFeature(
152                     (TypeEffectiveStatement<?>) effectiveSubstatement, defaultValues)) {
153                 return true;
154             }
155         }
156
157         return false;
158     }
159
160     private static boolean containsIfFeature(final EffectiveStatement<?, ?> effectiveStatement) {
161         for (final EffectiveStatement<?, ?> effectiveSubstatement : effectiveStatement.effectiveSubstatements()) {
162             if (YangStmtMapping.IF_FEATURE.equals(effectiveSubstatement.statementDefinition())) {
163                 return true;
164             }
165         }
166         return false;
167     }
168 }