ceb7cd8693defb5bd21cc09903cafd4cccafbc9f
[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 com.google.common.base.Optional;
11 import java.math.BigDecimal;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
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<>();
27     private final List<List<LengthConstraint>> lengths = new ArrayList<>();
28     private final List<List<PatternConstraint>> patterns = new ArrayList<>();
29     private final List<Integer> fractionDigits = new ArrayList<>();
30
31     public TypeConstraints(final String moduleName, final int line) {
32         this.moduleName = moduleName;
33         this.line = line;
34     }
35
36     public List<RangeConstraint> getRange() {
37         if (ranges.size() < 2) {
38             return Collections.emptyList();
39         }
40
41         final List<RangeConstraint> resolved = ranges.get(0);
42         RangeConstraint firstRange = resolved.get(0);
43         RangeConstraint lastRange = resolved.get(resolved.size() - 1);
44         Number min = firstRange.getMin();
45         Number max = lastRange.getMax();
46
47         if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
48             if (ranges.size() > 1) {
49                 validateRange(resolved);
50             }
51             return resolved;
52         }
53
54         if (firstRange.equals(lastRange)) {
55             if (min instanceof UnknownBoundaryNumber) {
56                 min = resolveMinRange(min);
57             }
58             if (max instanceof UnknownBoundaryNumber) {
59                 max = resolveMaxRange(max);
60             }
61             firstRange = BaseConstraints.newRangeConstraint(min, max,
62                 Optional.fromNullable(firstRange.getDescription()),
63                 Optional.fromNullable(firstRange.getReference()));
64             resolved.set(0, firstRange);
65             lastRange = BaseConstraints.newRangeConstraint(min, max,
66                 Optional.fromNullable(lastRange.getDescription()),
67                 Optional.fromNullable(lastRange.getReference()));
68             resolved.set(resolved.size() - 1, lastRange);
69         } else {
70             if (min instanceof UnknownBoundaryNumber) {
71                 min = resolveMinRange(min);
72                 firstRange = BaseConstraints.newRangeConstraint(min, firstRange.getMax(),
73                     Optional.fromNullable(firstRange.getDescription()),
74                     Optional.fromNullable(firstRange.getReference()));
75                 resolved.set(0, firstRange);
76             }
77             if (max instanceof UnknownBoundaryNumber) {
78                 max = resolveMaxRange(max);
79                 lastRange = BaseConstraints.newRangeConstraint(lastRange.getMin(), max,
80                     Optional.fromNullable(lastRange.getDescription()),
81                     Optional.fromNullable(lastRange.getReference()));
82                 resolved.set(resolved.size() - 1, lastRange);
83             }
84         }
85         if (this.ranges.size() > 1) {
86             validateRange(resolved);
87         }
88         return resolved;
89     }
90
91     private Number resolveMinRange(final Number min) {
92         int i = 1;
93         Number newMin = min;
94         while (newMin instanceof UnknownBoundaryNumber) {
95             final List<RangeConstraint> act = ranges.get(i);
96             newMin = act.get(0).getMin();
97             i++;
98         }
99         return newMin;
100     }
101
102     private Number resolveMaxRange(final Number max) {
103         int i = 1;
104         Number newMax = max;
105         while (newMax instanceof UnknownBoundaryNumber) {
106             final List<RangeConstraint> act = ranges.get(i);
107             newMax = act.get(act.size() - 1).getMax();
108             i++;
109         }
110         return newMax;
111     }
112
113     public void addRanges(final List<RangeConstraint> ranges) {
114         if (ranges != null && !(ranges.isEmpty())) {
115             this.ranges.add(ranges);
116         }
117     }
118
119     public List<List<LengthConstraint>> getAllLengths() {
120         return lengths;
121     }
122
123     public List<LengthConstraint> getLength() {
124         if (lengths.size() < 2) {
125             return Collections.emptyList();
126         }
127
128         final List<LengthConstraint> resolved = lengths.get(0);
129         LengthConstraint firstLength = resolved.get(0);
130         LengthConstraint lastLength = resolved.get(resolved.size() - 1);
131         Number min = firstLength.getMin();
132         Number max = lastLength.getMax();
133
134         if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
135             if (lengths.size() > 1) {
136                 validateLength(resolved);
137             }
138             return resolved;
139         }
140
141         if (firstLength.equals(lastLength)) {
142             if (min instanceof UnknownBoundaryNumber) {
143                 min = resolveMinLength(min);
144             }
145             if (max instanceof UnknownBoundaryNumber) {
146                 max = resolveMaxLength(max);
147             }
148             firstLength = BaseConstraints.newLengthConstraint(min, max,
149                 Optional.fromNullable(firstLength.getDescription()),
150                 Optional.fromNullable(firstLength.getReference()));
151             resolved.set(0, firstLength);
152             lastLength = BaseConstraints.newLengthConstraint(min, max,
153                 Optional.fromNullable(lastLength.getDescription()),
154                 Optional.fromNullable(lastLength.getReference()));
155             resolved.set(resolved.size() - 1, lastLength);
156         } else {
157             if (min instanceof UnknownBoundaryNumber) {
158                 min = resolveMinLength(min);
159                 firstLength = BaseConstraints.newLengthConstraint(min, firstLength.getMax(),
160                     Optional.fromNullable(firstLength.getDescription()),
161                     Optional.fromNullable(firstLength.getReference()));
162                 resolved.set(0, firstLength);
163             }
164             if (max instanceof UnknownBoundaryNumber) {
165                 max = resolveMaxLength(max);
166                 lastLength = BaseConstraints.newLengthConstraint(lastLength.getMin(), max,
167                     Optional.fromNullable(lastLength.getDescription()),
168                     Optional.fromNullable(lastLength.getReference()));
169                 resolved.set(resolved.size() - 1, lastLength);
170             }
171         }
172
173         if (lengths.size() > 1) {
174             validateLength(resolved);
175         }
176         return resolved;
177     }
178
179     private Number resolveMinLength(final Number min) {
180         int i = 1;
181         Number newMin = min;
182         while (newMin instanceof UnknownBoundaryNumber) {
183             final List<LengthConstraint> act = lengths.get(i);
184             newMin = act.get(0).getMin();
185             i++;
186         }
187         return newMin;
188     }
189
190     private Number resolveMaxLength(final Number max) {
191         int i = 1;
192         Number newMax = max;
193         while (newMax instanceof UnknownBoundaryNumber) {
194             final List<LengthConstraint> act = lengths.get(i);
195             newMax = act.get(act.size() - 1).getMax();
196             i++;
197         }
198         return newMax;
199     }
200
201     public void addLengths(final List<LengthConstraint> lengths) {
202         if (lengths != null && !(lengths.isEmpty())) {
203             this.lengths.add(lengths);
204         }
205     }
206
207     public List<PatternConstraint> getPatterns() {
208         if (patterns.isEmpty()) {
209             return Collections.emptyList();
210         }
211         return patterns.get(0);
212     }
213
214     public void addPatterns(final List<PatternConstraint> patterns) {
215         this.patterns.add(patterns);
216     }
217
218     public Integer getFractionDigits() {
219         if (fractionDigits.isEmpty()) {
220             return null;
221         }
222         return fractionDigits.get(0);
223     }
224
225     public void addFractionDigits(final Integer fractionDigits) {
226         this.fractionDigits.add(fractionDigits);
227     }
228
229     public void validateConstraints() {
230         validateLength();
231         validateRange();
232     }
233
234     private void validateRange() {
235         validateRange(getRange());
236     }
237
238     private void validateRange(final List<RangeConstraint> typeRange) {
239         if (ranges.size() < 2) {
240             return;
241         }
242
243         for (RangeConstraint range : typeRange) {
244             if (range.getMin() instanceof UnknownBoundaryNumber || range.getMax() instanceof UnknownBoundaryNumber) {
245                 throw new YangParseException(moduleName, line, "Unresolved range constraints");
246             }
247             final BigDecimal min = new BigDecimal(range.getMin().toString());
248             final BigDecimal max = new BigDecimal(range.getMax().toString());
249
250             List<RangeConstraint> parentRanges = ranges.get(1);
251             if (!areRangesSubintervalsOfParentRanges(parentRanges, min, max)) {
252                 throw new YangParseException(moduleName, line, "Invalid range constraint: <" + min + ", " + max
253                         + "> (parent: " + parentRanges + ").");
254             }
255         }
256     }
257
258     private boolean areRangesSubintervalsOfParentRanges(final List<RangeConstraint> parentRanges, final BigDecimal min,
259             final BigDecimal max) {
260         boolean check = false;
261         for (RangeConstraint r : parentRanges) {
262             Number parentMinNumber = r.getMin();
263             if (parentMinNumber instanceof UnknownBoundaryNumber) {
264                 parentMinNumber = resolveMinRange(parentMinNumber);
265             }
266             BigDecimal parentMin = new BigDecimal(parentMinNumber.toString());
267
268             Number parentMaxNumber = r.getMax();
269             if (parentMaxNumber instanceof UnknownBoundaryNumber) {
270                 parentMaxNumber = resolveMaxRange(parentMaxNumber);
271             }
272             BigDecimal parentMax = new BigDecimal(parentMaxNumber.toString());
273
274             if (parentMin.compareTo(min) <= 0 && parentMax.compareTo(max) >= 0) {
275                 check = true;
276                 break;
277             }
278         }
279         return check;
280     }
281
282     private void validateLength() {
283         validateLength(getLength());
284     }
285
286     private void validateLength(final List<LengthConstraint> typeLength) {
287         if (lengths.size() < 2) {
288             return;
289         }
290
291         for (LengthConstraint length : typeLength) {
292             if (length.getMin() instanceof UnknownBoundaryNumber || length.getMax() instanceof UnknownBoundaryNumber) {
293                 throw new YangParseException(moduleName, line, "Unresolved length constraints");
294             }
295             final long min = length.getMin().longValue();
296             final long max = length.getMax().longValue();
297
298             List<LengthConstraint> parentLengths = lengths.get(1);
299             if (!areLengthRangesSubintervalsOfParentLengthRanges(parentLengths, min, max)) {
300                 throw new YangParseException(moduleName, line, "Invalid length constraint: <" + min + ", " + max
301                         + "> (parent: " + parentLengths + ").");
302             }
303         }
304     }
305
306     private boolean areLengthRangesSubintervalsOfParentLengthRanges(final List<LengthConstraint> parentLengths,
307             final long min, final long max) {
308         boolean check = false;
309         for (LengthConstraint lc : parentLengths) {
310             Number parentMinNumber = lc.getMin();
311             if (parentMinNumber instanceof UnknownBoundaryNumber) {
312                 parentMinNumber = resolveMinLength(parentMinNumber);
313             }
314             long parentMin = parentMinNumber.longValue();
315
316             Number parentMaxNumber = lc.getMax();
317             if (parentMaxNumber instanceof UnknownBoundaryNumber) {
318                 parentMaxNumber = resolveMaxLength(parentMaxNumber);
319             }
320             long parentMax = parentMaxNumber.longValue();
321
322             if (parentMin <= min && parentMax >= max) {
323                 check = true;
324                 break;
325             }
326         }
327         return check;
328     }
329
330 }