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.stmt.rfc6020;
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Splitter;
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.ImmutableMap.Builder;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.collect.Iterables;
17 import java.math.BigDecimal;
18 import java.math.BigInteger;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.Comparator;
22 import java.util.Iterator;
23 import java.util.List;
26 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
29 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
30 import org.opendaylight.yangtools.yang.model.util.BinaryType;
31 import org.opendaylight.yangtools.yang.model.util.BooleanType;
32 import org.opendaylight.yangtools.yang.model.util.EmptyType;
33 import org.opendaylight.yangtools.yang.model.util.Int16;
34 import org.opendaylight.yangtools.yang.model.util.Int32;
35 import org.opendaylight.yangtools.yang.model.util.Int64;
36 import org.opendaylight.yangtools.yang.model.util.Int8;
37 import org.opendaylight.yangtools.yang.model.util.StringType;
38 import org.opendaylight.yangtools.yang.model.util.Uint16;
39 import org.opendaylight.yangtools.yang.model.util.Uint32;
40 import org.opendaylight.yangtools.yang.model.util.Uint64;
41 import org.opendaylight.yangtools.yang.model.util.Uint8;
42 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.LengthConstraintEffectiveImpl;
43 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.RangeConstraintEffectiveImpl;
44 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.TypeDefinitionEffectiveBuilder;
45 import org.opendaylight.yangtools.yang.parser.util.UnknownBoundaryNumber;
48 * util class for manipulating YANG base and extended types implementation
50 public final class TypeUtils {
52 public static final String BINARY = "binary";
53 public static final String BITS = "bits";
54 public static final String BOOLEAN = "boolean";
55 public static final String DECIMAL64 = "decimal64";
56 public static final String EMPTY = "empty";
57 public static final String ENUMERATION = "enumeration";
58 public static final String IDENTITY_REF = "identityref";
59 public static final String INSTANCE_IDENTIFIER = "instance-identifier";
60 public static final String INT8 = "int8";
61 public static final String INT16 = "int16";
62 public static final String INT32 = "int32";
63 public static final String INT64 = "int64";
64 public static final String LEAF_REF = "leafref";
65 public static final String STRING = "string";
66 public static final String UINT8 = "uint8";
67 public static final String UINT16 = "uint16";
68 public static final String UINT32 = "uint32";
69 public static final String UINT64 = "uint64";
70 public static final String UNION = "union";
72 private static final Set<String> BUILT_IN_TYPES = ImmutableSet.of(
73 BINARY, BITS, BOOLEAN, DECIMAL64, EMPTY, ENUMERATION, IDENTITY_REF, INSTANCE_IDENTIFIER,
74 INT8, INT16, INT32, INT64, LEAF_REF, STRING, UINT8, UINT16, UINT32, UINT64, UNION);
76 public static final Set<String> TYPE_BODY_STMTS = ImmutableSet.of(
77 DECIMAL64, ENUMERATION, LEAF_REF, IDENTITY_REF, INSTANCE_IDENTIFIER, BITS, UNION);
79 public static final Map<String, TypeDefinition<?>> PRIMITIVE_TYPES_MAP;
81 Builder<String, TypeDefinition<?>> b = ImmutableMap.<String, TypeDefinition<?>>builder();
82 b.put(BINARY, BinaryType.getInstance());
83 b.put(BOOLEAN, BooleanType.getInstance());
84 b.put(EMPTY, EmptyType.getInstance());
85 b.put(INT8, Int8.getInstance());
86 b.put(INT16, Int16.getInstance());
87 b.put(INT32, Int32.getInstance());
88 b.put(INT64, Int64.getInstance());
89 b.put(STRING, StringType.getInstance());
90 b.put(UINT8, Uint8.getInstance());
91 b.put(UINT16, Uint16.getInstance());
92 b.put(UINT32, Uint32.getInstance());
93 b.put(UINT64, Uint64.getInstance());
94 PRIMITIVE_TYPES_MAP = b.build();
97 private static final Comparator<TypeDefinition<?>> TYPE_SORT_COMPARATOR = new Comparator<TypeDefinition<?>>() {
99 public int compare(final TypeDefinition<?> o1, final TypeDefinition<?> o2) {
100 return Boolean.compare(isBuiltInType(o2), isBuiltInType(o1));
104 private TypeUtils() {
107 private static final Splitter PIPE_SPLITTER = Splitter.on('|').trimResults();
108 private static final Splitter TWO_DOTS_SPLITTER = Splitter.on("..").trimResults();
110 private static BigDecimal yangConstraintToBigDecimal(final Number number) {
111 if (number instanceof UnknownBoundaryNumber) {
112 if (number.toString().equals("min")) {
113 return RangeStatementImpl.YANG_MIN_NUM;
115 return RangeStatementImpl.YANG_MAX_NUM;
118 return new BigDecimal(number.toString());
122 public static int compareNumbers(final Number n1, final Number n2) {
124 final BigDecimal num1 = yangConstraintToBigDecimal(n1);
125 final BigDecimal num2 = yangConstraintToBigDecimal(n2);
127 return new BigDecimal(num1.toString()).compareTo(new BigDecimal(num2.toString()));
130 private static Number parseIntegerConstraintValue(final String value) {
133 if (isMinOrMaxString(value)) {
134 result = new UnknownBoundaryNumber(value);
137 result = new BigInteger(value);
138 } catch (NumberFormatException e) {
139 throw new IllegalArgumentException(String.format("Value %s is not a valid integer", value), e);
145 private static Number parseDecimalConstraintValue(final String value) {
148 if (isMinOrMaxString(value)) {
149 result = new UnknownBoundaryNumber(value);
152 if (value.indexOf('.') != -1) {
153 result = new BigDecimal(value);
155 result = new BigInteger(value);
157 } catch (NumberFormatException e) {
158 throw new IllegalArgumentException(String.format("Value %s is not a valid decimal number", value), e);
164 private static boolean isMinOrMaxString(final String value) {
165 return "min".equals(value) || "max".equals(value);
168 public static List<RangeConstraint> parseRangeListFromString(final String rangeArgument) {
170 Optional<String> description = Optional.absent();
171 Optional<String> reference = Optional.absent();
173 List<RangeConstraint> rangeConstraints = new ArrayList<>();
175 for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) {
176 final Iterator<String> boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator();
177 final Number min = parseDecimalConstraintValue(boundaries.next());
180 if (boundaries.hasNext()) {
181 max = parseDecimalConstraintValue(boundaries.next());
183 // if min larger than max then error
184 if (compareNumbers(min, max) == 1) {
185 throw new IllegalArgumentException(String.format(
186 "Range constraint %s has descending order of boundaries; should be ascending", singleRange));
188 if (boundaries.hasNext()) {
189 throw new IllegalArgumentException("Wrong number of boundaries in range constraint " + singleRange);
195 // some of intervals overlapping
196 if (rangeConstraints.size() > 1 && compareNumbers(min, Iterables.getLast(rangeConstraints).getMax()) != 1) {
197 throw new IllegalArgumentException(String.format("Some of the ranges in %s are not disjoint",
201 rangeConstraints.add(new RangeConstraintEffectiveImpl(min, max, description, reference));
204 return rangeConstraints;
207 public static List<LengthConstraint> parseLengthListFromString(final String rangeArgument) {
209 Optional<String> description = Optional.absent();
210 Optional<String> reference = Optional.absent();
212 List<LengthConstraint> rangeConstraints = new ArrayList<>();
214 for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) {
215 final Iterator<String> boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator();
216 final Number min = parseIntegerConstraintValue(boundaries.next());
219 if (boundaries.hasNext()) {
220 max = parseIntegerConstraintValue(boundaries.next());
222 // if min larger than max then error
223 Preconditions.checkArgument(compareNumbers(min, max) != 1,
224 "Length constraint %s has descending order of boundaries; should be ascending", singleRange);
225 Preconditions.checkArgument(!boundaries.hasNext(), "Wrong number of boundaries in length constraint %s",
231 // some of intervals overlapping
232 if (rangeConstraints.size() > 1 && compareNumbers(min, Iterables.getLast(rangeConstraints).getMax()) != 1) {
233 throw new IllegalArgumentException(String.format("Some of the length ranges in %s are not disjoint",
237 rangeConstraints.add(new LengthConstraintEffectiveImpl(min, max, description, reference));
240 return rangeConstraints;
243 public static boolean isBuiltInType(final TypeDefinition<?> o1) {
244 return BUILT_IN_TYPES.contains(o1.getQName().getLocalName());
247 public static boolean isYangBuiltInTypeString(final String typeName) {
248 return BUILT_IN_TYPES.contains(typeName);
251 public static boolean isYangPrimitiveTypeString(final String typeName) {
252 return PRIMITIVE_TYPES_MAP.containsKey(typeName);
255 public static boolean isYangTypeBodyStmtString(final String typeName) {
256 return TYPE_BODY_STMTS.contains(typeName);
259 public static TypeDefinition<?> getYangPrimitiveTypeFromString(final String typeName) {
260 return PRIMITIVE_TYPES_MAP.get(typeName);
263 public static TypeDefinition<?> getTypeFromEffectiveStatement(final EffectiveStatement<?, ?> effectiveStatement) {
264 if (effectiveStatement instanceof TypeDefinitionEffectiveBuilder) {
265 TypeDefinitionEffectiveBuilder typeDefEffectiveBuilder = (TypeDefinitionEffectiveBuilder) effectiveStatement;
266 return typeDefEffectiveBuilder.buildType();
268 final String typeName = ((TypeDefinition<?>) effectiveStatement).getQName().getLocalName();
269 return PRIMITIVE_TYPES_MAP.get(typeName);
273 public static void sortTypes(final List<TypeDefinition<?>> typesInit) {
274 Collections.sort(typesInit, TYPE_SORT_COMPARATOR);