Merge "Updated context references in yang-ext"
[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(final Number min) {
91         int i = 1;
92         Number newMin = min;
93         while (newMin instanceof UnknownBoundaryNumber) {
94             final List<RangeConstraint> act = ranges.get(i);
95             newMin = act.get(0).getMin();
96             i++;
97         }
98         return newMin;
99     }
100
101     private Number resolveMaxRange(final Number max) {
102         int i = 1;
103         Number newMax = max;
104         while (newMax instanceof UnknownBoundaryNumber) {
105             final List<RangeConstraint> act = ranges.get(i);
106             newMax = act.get(act.size() - 1).getMax();
107             i++;
108         }
109         return newMax;
110     }
111
112     public void addRanges(final List<RangeConstraint> ranges) {
113         if (ranges != null && !(ranges.isEmpty())) {
114             this.ranges.add(ranges);
115         }
116     }
117
118     public List<List<LengthConstraint>> getAllLengths() {
119         return lengths;
120     }
121
122     public List<LengthConstraint> getLength() {
123         if (lengths.size() < 2) {
124             return Collections.emptyList();
125         }
126
127         final List<LengthConstraint> resolved = lengths.get(0);
128         LengthConstraint firstLength = resolved.get(0);
129         LengthConstraint lastLength = resolved.get(resolved.size() - 1);
130         Number min = firstLength.getMin();
131         Number max = lastLength.getMax();
132
133         if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
134             if (lengths.size() > 1) {
135                 validateLength(resolved);
136             }
137             return resolved;
138         }
139
140         if (firstLength.equals(lastLength)) {
141             if (min instanceof UnknownBoundaryNumber) {
142                 min = resolveMinLength(min);
143             }
144             if (max instanceof UnknownBoundaryNumber) {
145                 max = resolveMaxLength(max);
146             }
147             firstLength = BaseConstraints.lengthConstraint(min, max, firstLength.getDescription(),
148                     firstLength.getReference());
149             resolved.set(0, firstLength);
150             lastLength = BaseConstraints.lengthConstraint(min, max, lastLength.getDescription(),
151                     lastLength.getReference());
152             resolved.set(resolved.size() - 1, lastLength);
153         } else {
154             if (min instanceof UnknownBoundaryNumber) {
155                 min = resolveMinLength(min);
156                 firstLength = BaseConstraints.lengthConstraint(min, firstLength.getMax(), firstLength.getDescription(),
157                         firstLength.getReference());
158                 resolved.set(0, firstLength);
159             }
160             if (max instanceof UnknownBoundaryNumber) {
161                 max = resolveMaxLength(max);
162                 lastLength = BaseConstraints.lengthConstraint(lastLength.getMin(), max, lastLength.getDescription(),
163                         lastLength.getReference());
164                 resolved.set(resolved.size() - 1, lastLength);
165             }
166         }
167
168         if (lengths.size() > 1) {
169             validateLength(resolved);
170         }
171         return resolved;
172     }
173
174     private Number resolveMinLength(final Number min) {
175         int i = 1;
176         Number newMin = min;
177         while (newMin instanceof UnknownBoundaryNumber) {
178             final List<LengthConstraint> act = lengths.get(i);
179             newMin = act.get(0).getMin();
180             i++;
181         }
182         return newMin;
183     }
184
185     private Number resolveMaxLength(final Number max) {
186         int i = 1;
187         Number newMax = max;
188         while (newMax instanceof UnknownBoundaryNumber) {
189             final List<LengthConstraint> act = lengths.get(i);
190             newMax = act.get(act.size() - 1).getMax();
191             i++;
192         }
193         return newMax;
194     }
195
196     public void addLengths(final List<LengthConstraint> lengths) {
197         if (lengths != null && !(lengths.isEmpty())) {
198             this.lengths.add(lengths);
199         }
200     }
201
202     public List<PatternConstraint> getPatterns() {
203         if (patterns.isEmpty()) {
204             return Collections.emptyList();
205         }
206         return patterns.get(0);
207     }
208
209     public void addPatterns(final List<PatternConstraint> patterns) {
210         this.patterns.add(patterns);
211     }
212
213     public Integer getFractionDigits() {
214         if (fractionDigits.isEmpty()) {
215             return null;
216         }
217         return fractionDigits.get(0);
218     }
219
220     public void addFractionDigits(final Integer fractionDigits) {
221         this.fractionDigits.add(fractionDigits);
222     }
223
224     public void validateConstraints() {
225         validateLength();
226         validateRange();
227     }
228
229     private void validateRange() {
230         validateRange(getRange());
231     }
232
233     private void validateRange(List<RangeConstraint> typeRange) {
234         if (ranges.size() < 2) {
235             return;
236         }
237
238         for (RangeConstraint range : typeRange) {
239             if (range.getMin() instanceof UnknownBoundaryNumber || range.getMax() instanceof UnknownBoundaryNumber) {
240                 throw new YangParseException(moduleName, line, "Unresolved range constraints");
241             }
242             final BigDecimal min = new BigDecimal(range.getMin().toString());
243             final BigDecimal max = new BigDecimal(range.getMax().toString());
244
245             List<RangeConstraint> parentRanges = ranges.get(1);
246             if (!areRangesSubintervalsOfParentRanges(parentRanges, min, max)) {
247                 throw new YangParseException(moduleName, line, "Invalid range constraint: <" + min + ", " + max
248                         + "> (parent: " + parentRanges + ").");
249             }
250         }
251     }
252
253     private boolean areRangesSubintervalsOfParentRanges(List<RangeConstraint> parentRanges, final BigDecimal min,
254             final BigDecimal max) {
255         boolean check = false;
256         for (RangeConstraint r : parentRanges) {
257             Number parentMinNumber = r.getMin();
258             if (parentMinNumber instanceof UnknownBoundaryNumber) {
259                 parentMinNumber = resolveMinRange(parentMinNumber);
260             }
261             BigDecimal parentMin = new BigDecimal(parentMinNumber.toString());
262
263             Number parentMaxNumber = r.getMax();
264             if (parentMaxNumber instanceof UnknownBoundaryNumber) {
265                 parentMaxNumber = resolveMaxRange(parentMaxNumber);
266             }
267             BigDecimal parentMax = new BigDecimal(parentMaxNumber.toString());
268
269             if (parentMin.compareTo(min) <= 0 && parentMax.compareTo(max) >= 0) {
270                 check = true;
271                 break;
272             }
273         }
274         return check;
275     }
276
277     private void validateLength() {
278         validateLength(getLength());
279     }
280
281     private void validateLength(List<LengthConstraint> typeLength) {
282         if (lengths.size() < 2) {
283             return;
284         }
285
286         for (LengthConstraint length : typeLength) {
287             if (length.getMin() instanceof UnknownBoundaryNumber || length.getMax() instanceof UnknownBoundaryNumber) {
288                 throw new YangParseException(moduleName, line, "Unresolved length constraints");
289             }
290             final long min = length.getMin().longValue();
291             final long max = length.getMax().longValue();
292
293             List<LengthConstraint> parentLengths = lengths.get(1);
294             if (!areLengthRangesSubintervalsOfParentLengthRanges(parentLengths, min, max)) {
295                 throw new YangParseException(moduleName, line, "Invalid length constraint: <" + min + ", " + max
296                         + "> (parent: " + parentLengths + ").");
297             }
298         }
299     }
300
301     private boolean areLengthRangesSubintervalsOfParentLengthRanges(final List<LengthConstraint> parentLengths,
302             final long min, final long max) {
303         boolean check = false;
304         for (LengthConstraint lc : parentLengths) {
305             Number parentMinNumber = lc.getMin();
306             if (parentMinNumber instanceof UnknownBoundaryNumber) {
307                 parentMinNumber = resolveMinLength(parentMinNumber);
308             }
309             long parentMin = parentMinNumber.longValue();
310
311             Number parentMaxNumber = lc.getMax();
312             if (parentMaxNumber instanceof UnknownBoundaryNumber) {
313                 parentMaxNumber = resolveMaxLength(parentMaxNumber);
314             }
315             long parentMax = parentMaxNumber.longValue();
316
317             if (parentMin <= min && parentMax >= max) {
318                 check = true;
319                 break;
320             }
321         }
322         return check;
323     }
324
325 }