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