X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fstmt%2Frfc6020%2FTypeUtils.java;h=68c55c886b876ce493eae6c12adedf5bf6efb010;hb=2a8123b50e46b6c46d97273ca7a7fa0dbfab485a;hp=3aee37027267ebd1a1e1c8f3e7db7d3bb1b1d355;hpb=afc9771f12441ce707dac07ad282fbbd4022bfb2;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/TypeUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/TypeUtils.java index 3aee370272..68c55c886b 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/TypeUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/TypeUtils.java @@ -10,18 +10,30 @@ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.YangVersion; import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +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.TypeEffectiveStatement; +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.LengthConstraint; import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint; +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; import org.opendaylight.yangtools.yang.model.util.UnresolvedNumber; import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException; import org.opendaylight.yangtools.yang.parser.spi.meta.QNameCacheNamespace; @@ -31,7 +43,7 @@ import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.Length import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.RangeConstraintEffectiveImpl; /** -* util class for manipulating YANG base and extended types implementation +* Utility class for manipulating YANG base and extended types implementation. */ public final class TypeUtils { @@ -55,9 +67,27 @@ public final class TypeUtils { public static final String UINT64 = "uint64"; public static final String UNION = "union"; - private static final Set BUILT_IN_TYPES = - ImmutableSet.of(BINARY, BITS, BOOLEAN, DECIMAL64, EMPTY, ENUMERATION, IDENTITY_REF, INSTANCE_IDENTIFIER, - INT8, INT16, INT32, INT64, LEAF_REF, STRING, UINT8, UINT16, UINT32, UINT64, UNION); + private static final Map BUILT_IN_TYPES = ImmutableMap.builder() + .put(BINARY, BINARY) + .put(BITS, BITS) + .put(BOOLEAN, BOOLEAN) + .put(DECIMAL64, DECIMAL64) + .put(EMPTY, EMPTY) + .put(ENUMERATION, ENUMERATION) + .put(IDENTITY_REF,IDENTITY_REF) + .put(INSTANCE_IDENTIFIER, INSTANCE_IDENTIFIER) + .put(INT8, INT8) + .put(INT16, INT16) + .put(INT32, INT32) + .put(INT64, INT64) + .put(LEAF_REF, LEAF_REF) + .put(STRING, STRING) + .put(UINT8, UINT8) + .put(UINT16, UINT16) + .put(UINT32, UINT32) + .put(UINT64, UINT64) + .put(UNION, UNION) + .build(); private static final Set TYPE_BODY_STMTS = ImmutableSet.of( DECIMAL64, ENUMERATION, LEAF_REF, IDENTITY_REF, BITS, UNION); @@ -96,7 +126,7 @@ public final class TypeUtils { try { return new BigInteger(value); - } catch (NumberFormatException e) { + } catch (final NumberFormatException e) { throw new SourceException(String.format("Value %s is not a valid integer", value), ctx.getStatementSourceReference(), e); } @@ -112,7 +142,7 @@ public final class TypeUtils { try { return value.indexOf('.') != -1 ? new BigDecimal(value) : new BigInteger(value); - } catch (NumberFormatException e) { + } catch (final NumberFormatException e) { throw new SourceException(String.format("Value %s is not a valid decimal number", value), ctx.getStatementSourceReference(), e); } @@ -121,10 +151,10 @@ public final class TypeUtils { public static List parseRangeListFromString(final StmtContext ctx, final String rangeArgument) { - Optional description = Optional.absent(); - Optional reference = Optional.absent(); + final Optional description = Optional.absent(); + final Optional reference = Optional.absent(); - List rangeConstraints = new ArrayList<>(); + final List rangeConstraints = new ArrayList<>(); for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) { final Iterator boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator(); @@ -135,23 +165,19 @@ public final class TypeUtils { max = parseDecimalConstraintValue(ctx, boundaries.next()); // if min larger than max then error - if (compareNumbers(min, max) == 1) { - throw new InferenceException(String.format( - "Range constraint %s has descending order of boundaries; should be ascending", - singleRange), ctx.getStatementSourceReference()); - } - if (boundaries.hasNext()) { - throw new SourceException(String.format("Wrong number of boundaries in range constraint %s", - singleRange), ctx.getStatementSourceReference()); - } + InferenceException.throwIf(compareNumbers(min, max) == 1, ctx.getStatementSourceReference(), + "Range constraint %s has descending order of boundaries; should be ascending", singleRange); + + SourceException.throwIf(boundaries.hasNext(), ctx.getStatementSourceReference(), + "Wrong number of boundaries in range constraint %s", singleRange); } else { max = min; } // some of intervals overlapping if (rangeConstraints.size() > 1 && compareNumbers(min, Iterables.getLast(rangeConstraints).getMax()) != 1) { - throw new InferenceException(String.format("Some of the ranges in %s are not disjoint", - rangeArgument), ctx.getStatementSourceReference()); + throw new InferenceException(ctx.getStatementSourceReference(), + "Some of the ranges in %s are not disjoint", rangeArgument); } rangeConstraints.add(new RangeConstraintEffectiveImpl(min, max, description, reference)); @@ -161,13 +187,13 @@ public final class TypeUtils { } public static List parseLengthListFromString(final StmtContext ctx, - final String rangeArgument) { - Optional description = Optional.absent(); - Optional reference = Optional.absent(); + final String lengthArgument) { + final Optional description = Optional.absent(); + final Optional reference = Optional.absent(); - List rangeConstraints = new ArrayList<>(); + final List lengthConstraints = new ArrayList<>(); - for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) { + for (final String singleRange : PIPE_SPLITTER.split(lengthArgument)) { final Iterator boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator(); final Number min = parseIntegerConstraintValue(ctx, boundaries.next()); @@ -176,26 +202,25 @@ public final class TypeUtils { max = parseIntegerConstraintValue(ctx, boundaries.next()); // if min larger than max then error - Preconditions.checkArgument(compareNumbers(min, max) != 1, - "Length constraint %s has descending order of boundaries; should be ascending. Statement source at %s", - singleRange, ctx.getStatementSourceReference()); - Preconditions.checkArgument(!boundaries.hasNext(), - "Wrong number of boundaries in length constraint %s. Statement source at %s", singleRange, - ctx.getStatementSourceReference()); + SourceException.throwIf(compareNumbers(min, max) == 1, ctx.getStatementSourceReference(), + "Length constraint %s has descending order of boundaries; should be ascending.", + singleRange); + SourceException.throwIf(boundaries.hasNext(), ctx.getStatementSourceReference(), + "Wrong number of boundaries in length constraint %s.", singleRange); } else { max = min; } // some of intervals overlapping - if (rangeConstraints.size() > 1 && compareNumbers(min, Iterables.getLast(rangeConstraints).getMax()) != 1) { - throw new InferenceException(String.format("Some of the length ranges in %s are not disjoint", - rangeArgument), ctx.getStatementSourceReference()); - } + InferenceException.throwIf(lengthConstraints.size() > 1 + && compareNumbers(min, Iterables.getLast(lengthConstraints).getMax()) != 1, + ctx.getStatementSourceReference(), "Some of the length ranges in %s are not disjoint", + lengthArgument); - rangeConstraints.add(new LengthConstraintEffectiveImpl(min, max, description, reference)); + lengthConstraints.add(new LengthConstraintEffectiveImpl(min, max, description, reference)); } - return rangeConstraints; + return lengthConstraints; } public static boolean isYangTypeBodyStmtString(final String typeName) { @@ -203,14 +228,106 @@ public final class TypeUtils { } public static boolean isYangBuiltInTypeString(final String typeName) { - return BUILT_IN_TYPES.contains(typeName); + return BUILT_IN_TYPES.containsKey(typeName); } public static SchemaPath typeEffectiveSchemaPath(final StmtContext stmtCtx) { final SchemaPath path = stmtCtx.getSchemaPath().get(); + final SchemaPath parent = path.getParent(); + final QName parentQName = parent.getLastComponent(); + Preconditions.checkArgument(parentQName != null, "Path %s has an empty parent", path); + final QName qname = stmtCtx.getFromNamespace(QNameCacheNamespace.class, - QName.create(path.getParent().getLastComponent(), path.getLastComponent().getLocalName())); - return path.getParent().createChild(qname); + QName.create(parentQName, path.getLastComponent().getLocalName())); + return parent.createChild(qname); + } + + /** + * Checks whether supplied type has any of specified default values marked + * with an if-feature. This method creates mutable copy of supplied set of + * default values. + * + * @param yangVersion + * yang version + * @param typeStmt + * type statement which should be checked + * @param defaultValues + * set of default values which should be checked. The method + * creates mutable copy of this set + * + * @return true if any of specified default values is marked with an + * if-feature, otherwise false + */ + public static boolean hasDefaultValueMarkedWithIfFeature(final YangVersion yangVersion, + final TypeEffectiveStatement typeStmt, final Set defaultValues) { + return !defaultValues.isEmpty() && yangVersion == YangVersion.VERSION_1_1 + && isRelevantForIfFeatureCheck(typeStmt) + && isAnyDefaultValueMarkedWithIfFeature(typeStmt, new HashSet<>(defaultValues)); + } + + /** + * Checks whether supplied type has specified default value marked with an + * if-feature. This method creates mutable set of supplied default value. + * + * @param yangVersion + * yang version + * @param typeStmt + * type statement which should be checked + * @param defaultValue + * default value to be checked + * + * @return true if specified default value is marked with an if-feature, + * otherwise false + */ + public static boolean hasDefaultValueMarkedWithIfFeature(final YangVersion yangVersion, + final TypeEffectiveStatement typeStmt, final String defaultValue) { + final HashSet defaultValues = new HashSet<>(); + defaultValues.add(defaultValue); + return !Strings.isNullOrEmpty(defaultValue) && yangVersion == YangVersion.VERSION_1_1 + && isRelevantForIfFeatureCheck(typeStmt) + && isAnyDefaultValueMarkedWithIfFeature(typeStmt, defaultValues); + } + + static String findBuiltinString(final String rawArgument) { + return BUILT_IN_TYPES.get(rawArgument); + } + + private static boolean isRelevantForIfFeatureCheck(final TypeEffectiveStatement typeStmt) { + final TypeDefinition typeDefinition = typeStmt.getTypeDefinition(); + return typeDefinition instanceof EnumTypeDefinition || typeDefinition instanceof BitsTypeDefinition + || typeDefinition instanceof UnionTypeDefinition; + } + + private static boolean isAnyDefaultValueMarkedWithIfFeature(final TypeEffectiveStatement typeStmt, + final Set defaultValues) { + final Iterator> iter = typeStmt.effectiveSubstatements().iterator(); + while (iter.hasNext() && !defaultValues.isEmpty()) { + final EffectiveStatement effectiveSubstatement = iter.next(); + if (YangStmtMapping.BIT.equals(effectiveSubstatement.statementDefinition())) { + final QName bitQName = (QName) effectiveSubstatement.argument(); + if (defaultValues.remove(bitQName.getLocalName()) && containsIfFeature(effectiveSubstatement)) { + return true; + } + } else if (YangStmtMapping.ENUM.equals(effectiveSubstatement.statementDefinition()) + && defaultValues.remove(effectiveSubstatement.argument()) + && containsIfFeature(effectiveSubstatement)) { + return true; + } else if (effectiveSubstatement instanceof TypeEffectiveStatement && isAnyDefaultValueMarkedWithIfFeature( + (TypeEffectiveStatement) effectiveSubstatement, defaultValues)) { + return true; + } + } + + return false; + } + + private static boolean containsIfFeature(final EffectiveStatement effectiveStatement) { + for (final EffectiveStatement effectiveSubstatement : effectiveStatement.effectiveSubstatements()) { + if (YangStmtMapping.IF_FEATURE.equals(effectiveSubstatement.statementDefinition())) { + return true; + } + } + return false; } }