Fixed types range validation.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / TypeConstraints.java
1 /*
2  * Copyright (c) 2013 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.util;
9
10 import java.math.BigDecimal;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
14
15 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
16 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
17 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
18 import org.opendaylight.yangtools.yang.model.util.BaseConstraints;
19
20 /**
21  * Holder object for holding YANG type constraints.
22  */
23 public final class TypeConstraints {
24     private final String moduleName;
25     private final int line;
26     private final List<List<RangeConstraint>> ranges = new ArrayList<List<RangeConstraint>>();
27     private final List<List<LengthConstraint>> lengths = new ArrayList<List<LengthConstraint>>();
28     private final List<List<PatternConstraint>> patterns = new ArrayList<List<PatternConstraint>>();
29     private final List<Integer> fractionDigits = new ArrayList<Integer>();
30
31     public TypeConstraints(final String moduleName, final int line) {
32         this.moduleName = moduleName;
33         this.line = line;
34     }
35
36     List<List<RangeConstraint>> getAllRanges() {
37         return ranges;
38     }
39
40     public List<RangeConstraint> getRange() {
41         if (ranges.size() < 2) {
42             return Collections.emptyList();
43         }
44
45         final List<RangeConstraint> resolved = ranges.get(0);
46         RangeConstraint firstRange = resolved.get(0);
47         RangeConstraint lastRange = resolved.get(resolved.size() - 1);
48         Number min = firstRange.getMin();
49         Number max = lastRange.getMax();
50
51         if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
52             if (ranges.size() > 1) {
53                 validateRange(resolved);
54             }
55             return resolved;
56         }
57
58         if (firstRange.equals(lastRange)) {
59             if (min instanceof UnknownBoundaryNumber) {
60                 min = resolveMinRange(min);
61             }
62             if (max instanceof UnknownBoundaryNumber) {
63                 max = resolveMaxRange(max);
64             }
65             firstRange = BaseConstraints.rangeConstraint(min, max, firstRange.getDescription(),
66                     firstRange.getReference());
67             resolved.set(0, firstRange);
68             lastRange = BaseConstraints.rangeConstraint(min, max, lastRange.getDescription(), lastRange.getReference());
69             resolved.set(resolved.size() - 1, lastRange);
70         } else {
71             if (min instanceof UnknownBoundaryNumber) {
72                 min = resolveMinRange(min);
73                 firstRange = BaseConstraints.rangeConstraint(min, firstRange.getMax(), firstRange.getDescription(),
74                         firstRange.getReference());
75                 resolved.set(0, firstRange);
76             }
77             if (max instanceof UnknownBoundaryNumber) {
78                 max = resolveMaxRange(max);
79                 lastRange = BaseConstraints.rangeConstraint(lastRange.getMin(), max, lastRange.getDescription(),
80                         lastRange.getReference());
81                 resolved.set(resolved.size() - 1, lastRange);
82             }
83         }
84         if (this.ranges.size() > 1) {
85             validateRange(resolved);
86         }
87         return resolved;
88     }
89
90     private Number resolveMinRange(Number min) {
91         int i = 1;
92         while (min instanceof UnknownBoundaryNumber) {
93             final List<RangeConstraint> act = ranges.get(i);
94             min = act.get(0).getMin();
95             i++;
96         }
97         return min;
98     }
99
100     private Number resolveMaxRange(Number max) {
101         int i = 1;
102         while (max instanceof UnknownBoundaryNumber) {
103             final List<RangeConstraint> act = ranges.get(i);
104             max = act.get(act.size() - 1).getMax();
105             i++;
106         }
107         return max;
108     }
109
110     public void addRanges(final List<RangeConstraint> ranges) {
111         if (ranges != null && !(ranges.isEmpty())) {
112             this.ranges.add(ranges);
113         }
114     }
115
116     public List<List<LengthConstraint>> getAllLengths() {
117         return lengths;
118     }
119
120     public List<LengthConstraint> getLength() {
121         if (lengths.size() < 2) {
122             return Collections.emptyList();
123         }
124
125         final List<LengthConstraint> resolved = lengths.get(0);
126         LengthConstraint firstLength = resolved.get(0);
127         LengthConstraint lastLength = resolved.get(resolved.size() - 1);
128         Number min = firstLength.getMin();
129         Number max = lastLength.getMax();
130
131         if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
132             if (lengths.size() > 1) {
133                 validateLength(resolved);
134             }
135             return resolved;
136         }
137
138         if (firstLength.equals(lastLength)) {
139             if (min instanceof UnknownBoundaryNumber) {
140                 min = resolveMinLength(min);
141             }
142             if (max instanceof UnknownBoundaryNumber) {
143                 max = resolveMaxLength(max);
144             }
145             firstLength = BaseConstraints.lengthConstraint(min, max, firstLength.getDescription(),
146                     firstLength.getReference());
147             resolved.set(0, firstLength);
148             lastLength = BaseConstraints.lengthConstraint(min, max, lastLength.getDescription(),
149                     lastLength.getReference());
150             resolved.set(resolved.size() - 1, lastLength);
151         } else {
152             if (min instanceof UnknownBoundaryNumber) {
153                 min = resolveMinLength(min);
154                 firstLength = BaseConstraints.lengthConstraint(min, firstLength.getMax(), firstLength.getDescription(),
155                         firstLength.getReference());
156                 resolved.set(0, firstLength);
157             }
158             if (max instanceof UnknownBoundaryNumber) {
159                 max = resolveMaxLength(max);
160                 lastLength = BaseConstraints.lengthConstraint(lastLength.getMin(), max, lastLength.getDescription(),
161                         lastLength.getReference());
162                 resolved.set(resolved.size() - 1, lastLength);
163             }
164         }
165
166         if (lengths.size() > 1) {
167             validateLength(resolved);
168         }
169         return resolved;
170     }
171
172     private Number resolveMinLength(Number min) {
173         int i = 1;
174         while (min instanceof UnknownBoundaryNumber) {
175             final List<LengthConstraint> act = lengths.get(i);
176             min = act.get(0).getMin();
177             i++;
178         }
179         return min;
180     }
181
182     private Number resolveMaxLength(Number max) {
183         int i = 1;
184         while (max instanceof UnknownBoundaryNumber) {
185             final List<LengthConstraint> act = lengths.get(i);
186             max = act.get(act.size() - 1).getMax();
187             i++;
188         }
189         return max;
190     }
191
192     public void addLengths(final List<LengthConstraint> lengths) {
193         if (lengths != null && !(lengths.isEmpty())) {
194             this.lengths.add(lengths);
195         }
196     }
197
198     public List<PatternConstraint> getPatterns() {
199         if(patterns.isEmpty()) {
200             return Collections.emptyList();
201         }
202         return patterns.get(0);
203     }
204
205     public void addPatterns(final List<PatternConstraint> patterns) {
206         this.patterns.add(patterns);
207     }
208
209     public Integer getFractionDigits() {
210         if (fractionDigits.isEmpty()) {
211             return null;
212         }
213         return fractionDigits.get(0);
214     }
215
216     public void addFractionDigits(final Integer fractionDigits) {
217         this.fractionDigits.add(fractionDigits);
218     }
219
220     public void validateConstraints() {
221         validateLength();
222         validateRange();
223     }
224
225     private void validateRange() {
226         if (ranges.size() < 2) {
227             return;
228         }
229         List<RangeConstraint> typeRange = getRange();
230
231         for (RangeConstraint range : typeRange) {
232             if (range.getMin() instanceof UnknownBoundaryNumber || range.getMax() instanceof UnknownBoundaryNumber) {
233                 throw new YangParseException(moduleName, line, "Unresolved range constraints");
234             }
235             final long min = range.getMin().longValue();
236             final long max = range.getMax().longValue();
237
238             List<RangeConstraint> parentRanges = ranges.get(1);
239             boolean check = false;
240             for (RangeConstraint r : parentRanges) {
241                 Number parentMinNumber = r.getMin();
242                 if (parentMinNumber instanceof UnknownBoundaryNumber) {
243                     parentMinNumber = resolveMinRange(parentMinNumber);
244                 }
245                 long parentMin = parentMinNumber.longValue();
246
247                 Number parentMaxNumber = r.getMax();
248                 if (parentMaxNumber instanceof UnknownBoundaryNumber) {
249                     parentMaxNumber = resolveMaxRange(parentMaxNumber);
250                 }
251                 long parentMax = parentMaxNumber.longValue();
252
253                 if (parentMin <= min && parentMax >= max) {
254                     check = true;
255                     break;
256                 }
257             }
258             if (!check) {
259                 throw new YangParseException(moduleName, line, "Invalid range constraint: <" + min + ", " + max
260                         + "> (parent: " + parentRanges + ").");
261             }
262         }
263     }
264
265     private void validateRange(List<RangeConstraint> typeRange) {
266         if (ranges.size() < 2) {
267             return;
268         }
269
270         for (RangeConstraint range : typeRange) {
271             if (range.getMin() instanceof UnknownBoundaryNumber || range.getMax() instanceof UnknownBoundaryNumber) {
272                 throw new YangParseException(moduleName, line, "Unresolved range constraints");
273             }
274             final BigDecimal min = new BigDecimal(range.getMin().toString());
275             final BigDecimal max = new BigDecimal(range.getMax().toString());
276
277             List<RangeConstraint> parentRanges = ranges.get(1);
278             boolean check = false;
279             for (RangeConstraint r : parentRanges) {
280                 Number parentMinNumber = r.getMin();
281                 if (parentMinNumber instanceof UnknownBoundaryNumber) {
282                     parentMinNumber = resolveMinRange(parentMinNumber);
283                 }
284                 BigDecimal parentMin = new BigDecimal(parentMinNumber.toString());
285
286                 Number parentMaxNumber = r.getMax();
287                 if (parentMaxNumber instanceof UnknownBoundaryNumber) {
288                     parentMaxNumber = resolveMaxRange(parentMaxNumber);
289                 }
290                 BigDecimal parentMax = new BigDecimal(parentMaxNumber.toString());
291
292                 if(parentMin.compareTo(min) <=0 && parentMax.compareTo(max) >= 0) {
293                     check = true;
294                     break;
295                 }
296             }
297             if (!check) {
298                 throw new YangParseException(moduleName, line, "Invalid range constraint: <" + min + ", " + max
299                         + "> (parent: " + parentRanges + ").");
300             }
301         }
302     }
303
304     private void validateLength() {
305         if (lengths.size() < 2) {
306             return;
307         }
308         List<LengthConstraint> typeLength = getLength();
309
310         for (LengthConstraint length : typeLength) {
311             if (length.getMin() instanceof UnknownBoundaryNumber || length.getMax() instanceof UnknownBoundaryNumber) {
312                 throw new YangParseException(moduleName, line, "Unresolved length constraints");
313             }
314             final long min = length.getMin().longValue();
315             final long max = length.getMax().longValue();
316
317             List<LengthConstraint> parentLengths = lengths.get(1);
318             boolean check = false;
319             for (LengthConstraint lc : parentLengths) {
320                 Number parentMinNumber = lc.getMin();
321                 if (parentMinNumber instanceof UnknownBoundaryNumber) {
322                     parentMinNumber = resolveMinLength(parentMinNumber);
323                 }
324                 long parentMin = parentMinNumber.longValue();
325
326                 Number parentMaxNumber = lc.getMax();
327                 if (parentMaxNumber instanceof UnknownBoundaryNumber) {
328                     parentMaxNumber = resolveMaxLength(parentMaxNumber);
329                 }
330                 long parentMax = parentMaxNumber.longValue();
331
332                 if (parentMin <= min && parentMax >= max) {
333                     check = true;
334                     break;
335                 }
336             }
337             if (!check) {
338                 throw new YangParseException(moduleName, line, "Invalid length constraint: <" + min + ", " + max
339                         + "> (parent: " + parentLengths + ").");
340             }
341         }
342     }
343
344     private void validateLength(List<LengthConstraint> typeLength) {
345         if (lengths.size() < 2) {
346             return;
347         }
348
349         for (LengthConstraint length : typeLength) {
350             if (length.getMin() instanceof UnknownBoundaryNumber || length.getMax() instanceof UnknownBoundaryNumber) {
351                 throw new YangParseException(moduleName, line, "Unresolved length constraints");
352             }
353             final long min = length.getMin().longValue();
354             final long max = length.getMax().longValue();
355
356             List<LengthConstraint> parentLengths = lengths.get(1);
357             boolean check = false;
358             for (LengthConstraint lc : parentLengths) {
359                 Number parentMinNumber = lc.getMin();
360                 if (parentMinNumber instanceof UnknownBoundaryNumber) {
361                     parentMinNumber = resolveMinLength(parentMinNumber);
362                 }
363                 long parentMin = parentMinNumber.longValue();
364
365                 Number parentMaxNumber = lc.getMax();
366                 if (parentMaxNumber instanceof UnknownBoundaryNumber) {
367                     parentMaxNumber = resolveMaxLength(parentMaxNumber);
368                 }
369                 long parentMax = parentMaxNumber.longValue();
370
371                 if (parentMin <= min && parentMax >= max) {
372                     check = true;
373                     break;
374                 }
375             }
376             if (!check) {
377                 throw new YangParseException(moduleName, line, "Invalid length constraint: <" + min + ", " + max
378                         + "> (parent: " + parentLengths + ").");
379             }
380         }
381     }
382
383 }