Bug 3670 (part 1/5): Use of new statement parser in yang-maven-plugin
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / TypeUtils.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 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Splitter;
12 import com.google.common.collect.Iterables;
13 import java.math.BigDecimal;
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.Comparator;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
27 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
28 import org.opendaylight.yangtools.yang.model.util.BinaryType;
29 import org.opendaylight.yangtools.yang.model.util.BooleanType;
30 import org.opendaylight.yangtools.yang.model.util.EmptyType;
31 import org.opendaylight.yangtools.yang.model.util.Int16;
32 import org.opendaylight.yangtools.yang.model.util.Int32;
33 import org.opendaylight.yangtools.yang.model.util.Int64;
34 import org.opendaylight.yangtools.yang.model.util.Int8;
35 import org.opendaylight.yangtools.yang.model.util.StringType;
36 import org.opendaylight.yangtools.yang.model.util.Uint16;
37 import org.opendaylight.yangtools.yang.model.util.Uint32;
38 import org.opendaylight.yangtools.yang.model.util.Uint64;
39 import org.opendaylight.yangtools.yang.model.util.Uint8;
40 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.LengthConstraintEffectiveImpl;
41 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.RangeConstraintEffectiveImpl;
42 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.TypeDefinitionEffectiveBuilder;
43 import org.opendaylight.yangtools.yang.parser.util.UnknownBoundaryNumber;
44
45 /**
46 * util class for manipulating YANG base and extended types implementation
47 */
48 public final class TypeUtils {
49
50     public static final String BINARY = "binary";
51     public static final String BITS = "bits";
52     public static final String BOOLEAN = "boolean";
53     public static final String DECIMAL64 = "decimal64";
54     public static final String EMPTY = "empty";
55     public static final String ENUMERATION = "enumeration";
56     public static final String IDENTITY_REF = "identityref";
57     public static final String INSTANCE_IDENTIFIER = "instance-identifier";
58     public static final String INT8 = "int8";
59     public static final String INT16 = "int16";
60     public static final String INT32 = "int32";
61     public static final String INT64 = "int64";
62     public static final String LEAF_REF = "leafref";
63     public static final String STRING = "string";
64     public static final String UINT8 = "uint8";
65     public static final String UINT16 = "uint16";
66     public static final String UINT32 = "uint32";
67     public static final String UINT64 = "uint64";
68     public static final String UNION = "union";
69
70     private static final Set<String> BUILT_IN_TYPES = new HashSet<>();
71     public static final Set<String> TYPE_BODY_STMTS = new HashSet<>();
72     public static final Map<String, TypeDefinition<?>> PRIMITIVE_TYPES_MAP = new HashMap<>();
73
74     private static final Comparator<TypeDefinition<?>> TYPE_SORT_COMPARATOR = new Comparator<TypeDefinition<?>>() {
75         @Override
76         public int compare(TypeDefinition<?> o1, TypeDefinition<?> o2) {
77             if (isBuiltInType(o1) && !isBuiltInType(o2)) {
78                 return -1;
79             }
80             if (!isBuiltInType(o1) && isBuiltInType(o2)) {
81                 return 1;
82             }
83             return 0;
84         }
85     };
86     static {
87
88 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,BINARY));
89 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,BITS));
90 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,BOOLEAN));
91 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,DECIMAL64));
92 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,EMPTY));
93 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,ENUMERATION));
94 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,IDENTITY_REF));
95 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,INSTANCE_IDENTIFIER));
96 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,INT8));
97 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,INT16));
98 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,INT32));
99 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,INT64));
100 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,LEAF_REF));
101 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,STRING));
102 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,UINT8));
103 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,UINT16));
104 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,UINT32));
105 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,UINT64));
106 //        BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,UNION));
107
108         BUILT_IN_TYPES.add(BINARY);
109         BUILT_IN_TYPES.add(BITS);
110         BUILT_IN_TYPES.add(BOOLEAN);
111         BUILT_IN_TYPES.add(DECIMAL64);
112         BUILT_IN_TYPES.add(EMPTY);
113         BUILT_IN_TYPES.add(ENUMERATION);
114         BUILT_IN_TYPES.add(IDENTITY_REF);
115         BUILT_IN_TYPES.add(INSTANCE_IDENTIFIER);
116         BUILT_IN_TYPES.add(INT8);
117         BUILT_IN_TYPES.add(INT16);
118         BUILT_IN_TYPES.add(INT32);
119         BUILT_IN_TYPES.add(INT64);
120         BUILT_IN_TYPES.add(LEAF_REF);
121         BUILT_IN_TYPES.add(STRING);
122         BUILT_IN_TYPES.add(UINT8);
123         BUILT_IN_TYPES.add(UINT16);
124         BUILT_IN_TYPES.add(UINT32);
125         BUILT_IN_TYPES.add(UINT64);
126         BUILT_IN_TYPES.add(UNION);
127
128         TYPE_BODY_STMTS.add(DECIMAL64);
129         TYPE_BODY_STMTS.add(ENUMERATION);
130         TYPE_BODY_STMTS.add(LEAF_REF);
131         TYPE_BODY_STMTS.add(IDENTITY_REF);
132         TYPE_BODY_STMTS.add(INSTANCE_IDENTIFIER);
133         TYPE_BODY_STMTS.add(BITS);
134         TYPE_BODY_STMTS.add(UNION);
135
136         PRIMITIVE_TYPES_MAP.put(BINARY, BinaryType.getInstance());
137         PRIMITIVE_TYPES_MAP.put(BOOLEAN, BooleanType.getInstance());
138         PRIMITIVE_TYPES_MAP.put(EMPTY, EmptyType.getInstance());
139         PRIMITIVE_TYPES_MAP.put(INT8, Int8.getInstance());
140         PRIMITIVE_TYPES_MAP.put(INT16, Int16.getInstance());
141         PRIMITIVE_TYPES_MAP.put(INT32, Int32.getInstance());
142         PRIMITIVE_TYPES_MAP.put(INT64, Int64.getInstance());
143         PRIMITIVE_TYPES_MAP.put(STRING, StringType.getInstance());
144         PRIMITIVE_TYPES_MAP.put(UINT8, Uint8.getInstance());
145         PRIMITIVE_TYPES_MAP.put(UINT16, Uint16.getInstance());
146         PRIMITIVE_TYPES_MAP.put(UINT32, Uint32.getInstance());
147         PRIMITIVE_TYPES_MAP.put(UINT64, Uint64.getInstance());
148     }
149
150     private TypeUtils() {
151     }
152
153     private static final Splitter PIPE_SPLITTER = Splitter.on('|').trimResults();
154     private static final Splitter TWO_DOTS_SPLITTER = Splitter.on("..").trimResults();
155
156     private static BigDecimal yangConstraintToBigDecimal(Number number) {
157         if (number instanceof UnknownBoundaryNumber) {
158             if (number.toString().equals("min")) {
159                 return RangeStatementImpl.YANG_MIN_NUM;
160             } else {
161                 return RangeStatementImpl.YANG_MAX_NUM;
162             }
163         } else {
164             return new BigDecimal(number.toString());
165         }
166     }
167
168     public static int compareNumbers(Number n1, Number n2) {
169
170         final BigDecimal num1 = yangConstraintToBigDecimal(n1);
171         final BigDecimal num2 = yangConstraintToBigDecimal(n2);
172
173         return new BigDecimal(num1.toString()).compareTo(new BigDecimal(num2.toString()));
174     }
175
176     private static Number parseIntegerConstraintValue(final String value) {
177         Number result;
178
179         if (isMinOrMaxString(value)) {
180             result = new UnknownBoundaryNumber(value);
181         } else {
182             try {
183                 result = new BigInteger(value);
184             } catch (NumberFormatException e) {
185                 throw new IllegalArgumentException(String.format("Value %s is not a valid integer", value), e);
186             }
187         }
188         return result;
189     }
190
191     private static Number parseDecimalConstraintValue(final String value) {
192         final Number result;
193
194         if (isMinOrMaxString(value)) {
195             result = new UnknownBoundaryNumber(value);
196         } else {
197             try {
198                 if (value.indexOf('.') != -1) {
199                     result = new BigDecimal(value);
200                 } else {
201                     result = new BigInteger(value);
202                 }
203             } catch (NumberFormatException e) {
204                 throw new IllegalArgumentException(String.format("Value %s is not a valid decimal number", value), e);
205             }
206         }
207         return result;
208     }
209
210     private static boolean isMinOrMaxString(final String value) {
211         return "min".equals(value) || "max".equals(value);
212     }
213
214     public static List<RangeConstraint> parseRangeListFromString(String rangeArgument) {
215
216         Optional<String> description = Optional.absent();
217         Optional<String> reference = Optional.absent();
218
219         List<RangeConstraint> rangeConstraints = new ArrayList<>();
220
221         for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) {
222             final Iterator<String> boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator();
223             final Number min = parseDecimalConstraintValue(boundaries.next());
224
225             final Number max;
226             if (boundaries.hasNext()) {
227                 max = parseDecimalConstraintValue(boundaries.next());
228
229                 // if min larger than max then error
230                 if (compareNumbers(min, max) == 1) {
231                     throw new IllegalArgumentException(String.format(
232                             "Range constraint %s has descending order of boundaries; should be ascending", singleRange));
233                 }
234                 if (boundaries.hasNext()) {
235                     throw new IllegalArgumentException("Wrong number of boundaries in range constraint " + singleRange);
236                 }
237             } else {
238                 max = min;
239             }
240
241             // some of intervals overlapping
242             if (rangeConstraints.size() > 1 && compareNumbers(min, Iterables.getLast(rangeConstraints).getMax()) != 1) {
243                 throw new IllegalArgumentException(String.format("Some of the ranges in %s are not disjoint",
244                         rangeArgument));
245             }
246
247             rangeConstraints.add(new RangeConstraintEffectiveImpl(min, max, description, reference));
248         }
249
250         return rangeConstraints;
251     }
252
253     public static List<LengthConstraint> parseLengthListFromString(String rangeArgument) {
254
255         Optional<String> description = Optional.absent();
256         Optional<String> reference = Optional.absent();
257
258         List<LengthConstraint> rangeConstraints = new ArrayList<>();
259
260         for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) {
261             final Iterator<String> boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator();
262             final Number min = parseIntegerConstraintValue(boundaries.next());
263
264             final Number max;
265             if (boundaries.hasNext()) {
266                 max = parseIntegerConstraintValue(boundaries.next());
267
268                 // if min larger than max then error
269                 if (compareNumbers(min, max) == 1) {
270                     throw new IllegalArgumentException(
271                             String.format(
272                                     "Length constraint %s has descending order of boundaries; should be ascending",
273                                     singleRange));
274                 }
275                 if (boundaries.hasNext()) {
276                     throw new IllegalArgumentException("Wrong number of boundaries in length constraint " + singleRange);
277                 }
278             } else {
279                 max = min;
280             }
281
282             // some of intervals overlapping
283             if (rangeConstraints.size() > 1 && compareNumbers(min, Iterables.getLast(rangeConstraints).getMax()) != 1) {
284                 throw new IllegalArgumentException(String.format("Some of the length ranges in %s are not disjoint",
285                         rangeArgument));
286             }
287
288             rangeConstraints.add(new LengthConstraintEffectiveImpl(min, max, description, reference));
289         }
290
291         return rangeConstraints;
292     }
293
294     public static boolean isBuiltInType(TypeDefinition<?> o1) {
295         return BUILT_IN_TYPES.contains(o1.getQName().getLocalName());
296     }
297
298     public static boolean isYangBuiltInTypeString(String typeName) {
299         return BUILT_IN_TYPES.contains(typeName);
300     }
301
302     public static boolean isYangPrimitiveTypeString(String typeName) {
303         return PRIMITIVE_TYPES_MAP.containsKey(typeName);
304     }
305
306     public static boolean isYangTypeBodyStmtString(String typeName) {
307         return TYPE_BODY_STMTS.contains(typeName);
308     }
309
310     public static TypeDefinition<?> getYangPrimitiveTypeFromString(String typeName) {
311         if (PRIMITIVE_TYPES_MAP.containsKey(typeName)) {
312             return PRIMITIVE_TYPES_MAP.get(typeName);
313         }
314         return null;
315     }
316
317     public static TypeDefinition<?> getTypeFromEffectiveStatement(EffectiveStatement<?, ?> effectiveStatement) {
318         if (effectiveStatement instanceof TypeDefinitionEffectiveBuilder) {
319             TypeDefinitionEffectiveBuilder typeDefEffectiveBuilder = (TypeDefinitionEffectiveBuilder) effectiveStatement;
320             return typeDefEffectiveBuilder.buildType();
321         } else {
322             final String typeName = ((TypeDefinition<?>) effectiveStatement).getQName().getLocalName();
323             return PRIMITIVE_TYPES_MAP.get(typeName);
324         }
325     }
326
327     public static void sortTypes(List<TypeDefinition<?>> typesInit) {
328         Collections.sort(typesInit, TYPE_SORT_COMPARATOR);
329     }
330
331 }