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=8f832ca79cfde8e868446209f31207d81f8f4bfb;hb=b246beeb2931748a264f188b914039a3ad3d5096;hp=9b9683d41c34d0cd828112daea6bc7b647c75b62;hpb=387d6385bbd6a689372c6ac9cdde4021a7162e4d;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 9b9683d41c..8f832ca79c 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 @@ -7,29 +7,39 @@ */ 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.type.LengthConstraint; -import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint; -import org.opendaylight.yangtools.yang.model.util.UnresolvedNumber; +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.stmt.UnresolvedNumber; +import org.opendaylight.yangtools.yang.model.api.stmt.ValueRange; +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; +import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException; import org.opendaylight.yangtools.yang.parser.spi.meta.QNameCacheNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.LengthConstraintEffectiveImpl; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.RangeConstraintEffectiveImpl; +import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; /** -* util class for manipulating YANG base and extended types implementation +* Utility class for manipulating YANG base and extended types implementation. */ public final class TypeUtils { @@ -53,9 +63,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); @@ -84,7 +112,7 @@ public final class TypeUtils { return new BigDecimal(num1.toString()).compareTo(new BigDecimal(num2.toString())); } - private static Number parseIntegerConstraintValue(final String value) { + private static Number parseIntegerConstraintValue(final StmtContext ctx, final String value) { if ("max".equals(value)) { return UnresolvedNumber.max(); } @@ -94,12 +122,12 @@ public final class TypeUtils { try { return new BigInteger(value); - } catch (NumberFormatException e) { - throw new IllegalArgumentException(String.format("Value %s is not a valid integer", value), e); + } catch (final NumberFormatException e) { + throw new SourceException(ctx.getStatementSourceReference(), e, "Value %s is not a valid integer", value); } } - private static Number parseDecimalConstraintValue(final String value) { + private static Number parseDecimalConstraintValue(final StmtContext ctx, final String value) { if ("max".equals(value)) { return UnresolvedNumber.max(); } @@ -109,84 +137,74 @@ public final class TypeUtils { try { return value.indexOf('.') != -1 ? new BigDecimal(value) : new BigInteger(value); - } catch (NumberFormatException e) { - throw new IllegalArgumentException(String.format("Value %s is not a valid decimal number", value), e); + } catch (final NumberFormatException e) { + throw new SourceException(String.format("Value %s is not a valid decimal number", value), + ctx.getStatementSourceReference(), e); } } - public static List parseRangeListFromString(final String rangeArgument) { - - Optional description = Optional.absent(); - Optional reference = Optional.absent(); - - List rangeConstraints = new ArrayList<>(); + public static List parseRangeListFromString(final StmtContext ctx, + final String rangeArgument) { + final List ranges = new ArrayList<>(); for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) { - final Iterator boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator(); - final Number min = parseDecimalConstraintValue(boundaries.next()); + final Iterator boundaries = TWO_DOTS_SPLITTER.split(singleRange).iterator(); + final Number min = parseDecimalConstraintValue(ctx, boundaries.next()); final Number max; if (boundaries.hasNext()) { - max = parseDecimalConstraintValue(boundaries.next()); + max = parseDecimalConstraintValue(ctx, boundaries.next()); // if min larger than max then error - if (compareNumbers(min, max) == 1) { - throw new IllegalArgumentException(String.format( - "Range constraint %s has descending order of boundaries; should be ascending", singleRange)); - } - if (boundaries.hasNext()) { - throw new IllegalArgumentException("Wrong number of boundaries in range constraint " + singleRange); - } + SourceException.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 IllegalArgumentException(String.format("Some of the ranges in %s are not disjoint", - rangeArgument)); - } - - rangeConstraints.add(new RangeConstraintEffectiveImpl(min, max, description, reference)); + InferenceException.throwIf(ranges.size() > 1 + && compareNumbers(min, Iterables.getLast(ranges).upperBound()) != 1, + ctx.getStatementSourceReference(), "Some of the value ranges in %s are not disjoint", + rangeArgument); + ranges.add(ValueRange.of(min, max)); } - return rangeConstraints; + return ranges; } - public static List parseLengthListFromString(final String rangeArgument) { + public static List parseLengthListFromString(final StmtContext ctx, + final String lengthArgument) { + final List ranges = new ArrayList<>(); - Optional description = Optional.absent(); - Optional reference = Optional.absent(); - - List rangeConstraints = new ArrayList<>(); - - for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) { - final Iterator boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator(); - final Number min = parseIntegerConstraintValue(boundaries.next()); + for (final String singleRange : PIPE_SPLITTER.split(lengthArgument)) { + final Iterator boundaries = TWO_DOTS_SPLITTER.split(singleRange).iterator(); + final Number min = parseIntegerConstraintValue(ctx, boundaries.next()); final Number max; if (boundaries.hasNext()) { - max = parseIntegerConstraintValue(boundaries.next()); + 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", singleRange); - Preconditions.checkArgument(!boundaries.hasNext(), "Wrong number of boundaries in length constraint %s", - singleRange); + 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 IllegalArgumentException(String.format("Some of the length ranges in %s are not disjoint", - rangeArgument)); - } - - rangeConstraints.add(new LengthConstraintEffectiveImpl(min, max, description, reference)); + InferenceException.throwIf(ranges.size() > 1 + && compareNumbers(min, Iterables.getLast(ranges).upperBound()) != 1, + ctx.getStatementSourceReference(), "Some of the length ranges in %s are not disjoint", + lengthArgument); + ranges.add(ValueRange.of(min, max)); } - return rangeConstraints; + return ranges; } public static boolean isYangTypeBodyStmtString(final String typeName) { @@ -194,14 +212,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; } }