Minor code refactoring.
[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<>();
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.rangeConstraint(min, max, firstRange.getDescription(),
62                     firstRange.getReference());
63             resolved.set(0, firstRange);
64             lastRange = BaseConstraints.rangeConstraint(min, max, lastRange.getDescription(), lastRange.getReference());
65             resolved.set(resolved.size() - 1, lastRange);
66         } else {
67             if (min instanceof UnknownBoundaryNumber) {
68                 min = resolveMinRange(min);
69                 firstRange = BaseConstraints.rangeConstraint(min, firstRange.getMax(), firstRange.getDescription(),
70                         firstRange.getReference());
71                 resolved.set(0, firstRange);
72             }
73             if (max instanceof UnknownBoundaryNumber) {
74                 max = resolveMaxRange(max);
75                 lastRange = BaseConstraints.rangeConstraint(lastRange.getMin(), max, lastRange.getDescription(),
76                         lastRange.getReference());
77                 resolved.set(resolved.size() - 1, lastRange);
78             }
79         }
80         if (this.ranges.size() > 1) {
81             validateRange(resolved);
82         }
83         return resolved;
84     }
85
86     private Number resolveMinRange(final Number min) {
87         int i = 1;
88         Number newMin = min;
89         while (newMin instanceof UnknownBoundaryNumber) {
90             final List<RangeConstraint> act = ranges.get(i);
91             newMin = act.get(0).getMin();
92             i++;
93         }
94         return newMin;
95     }
96
97     private Number resolveMaxRange(final Number max) {
98         int i = 1;
99         Number newMax = max;
100         while (newMax instanceof UnknownBoundaryNumber) {
101             final List<RangeConstraint> act = ranges.get(i);
102             newMax = act.get(act.size() - 1).getMax();
103             i++;
104         }
105         return newMax;
106     }
107
108     public void addRanges(final List<RangeConstraint> ranges) {
109         if (ranges != null && !(ranges.isEmpty())) {
110             this.ranges.add(ranges);
111         }
112     }
113
114     public List<List<LengthConstraint>> getAllLengths() {
115         return lengths;
116     }
117
118     public List<LengthConstraint> getLength() {
119         if (lengths.size() < 2) {
120             return Collections.emptyList();
121         }
122
123         final List<LengthConstraint> resolved = lengths.get(0);
124         LengthConstraint firstLength = resolved.get(0);
125         LengthConstraint lastLength = resolved.get(resolved.size() - 1);
126         Number min = firstLength.getMin();
127         Number max = lastLength.getMax();
128
129         if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
130             if (lengths.size() > 1) {
131                 validateLength(resolved);
132             }
133             return resolved;
134         }
135
136         if (firstLength.equals(lastLength)) {
137             if (min instanceof UnknownBoundaryNumber) {
138                 min = resolveMinLength(min);
139             }
140             if (max instanceof UnknownBoundaryNumber) {
141                 max = resolveMaxLength(max);
142             }
143             firstLength = BaseConstraints.lengthConstraint(min, max, firstLength.getDescription(),
144                     firstLength.getReference());
145             resolved.set(0, firstLength);
146             lastLength = BaseConstraints.lengthConstraint(min, max, lastLength.getDescription(),
147                     lastLength.getReference());
148             resolved.set(resolved.size() - 1, lastLength);
149         } else {
150             if (min instanceof UnknownBoundaryNumber) {
151                 min = resolveMinLength(min);
152                 firstLength = BaseConstraints.lengthConstraint(min, firstLength.getMax(), firstLength.getDescription(),
153                         firstLength.getReference());
154                 resolved.set(0, firstLength);
155             }
156             if (max instanceof UnknownBoundaryNumber) {
157                 max = resolveMaxLength(max);
158                 lastLength = BaseConstraints.lengthConstraint(lastLength.getMin(), max, lastLength.getDescription(),
159                         lastLength.getReference());
160                 resolved.set(resolved.size() - 1, lastLength);
161             }
162         }
163
164         if (lengths.size() > 1) {
165             validateLength(resolved);
166         }
167         return resolved;
168     }
169
170     private Number resolveMinLength(final Number min) {
171         int i = 1;
172         Number newMin = min;
173         while (newMin instanceof UnknownBoundaryNumber) {
174             final List<LengthConstraint> act = lengths.get(i);
175             newMin = act.get(0).getMin();
176             i++;
177         }
178         return newMin;
179     }
180
181     private Number resolveMaxLength(final Number max) {
182         int i = 1;
183         Number newMax = max;
184         while (newMax instanceof UnknownBoundaryNumber) {
185             final List<LengthConstraint> act = lengths.get(i);
186             newMax = act.get(act.size() - 1).getMax();
187             i++;
188         }
189         return newMax;
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         validateRange(getRange());
227     }
228
229     private void validateRange(List<RangeConstraint> typeRange) {
230         if (ranges.size() < 2) {
231             return;
232         }
233
234         for (RangeConstraint range : typeRange) {
235             if (range.getMin() instanceof UnknownBoundaryNumber || range.getMax() instanceof UnknownBoundaryNumber) {
236                 throw new YangParseException(moduleName, line, "Unresolved range constraints");
237             }
238             final BigDecimal min = new BigDecimal(range.getMin().toString());
239             final BigDecimal max = new BigDecimal(range.getMax().toString());
240
241             List<RangeConstraint> parentRanges = ranges.get(1);
242             if (!areRangesSubintervalsOfParentRanges(parentRanges, min, max)) {
243                 throw new YangParseException(moduleName, line, "Invalid range constraint: <" + min + ", " + max
244                         + "> (parent: " + parentRanges + ").");
245             }
246         }
247     }
248
249     private boolean areRangesSubintervalsOfParentRanges(List<RangeConstraint> parentRanges, final BigDecimal min,
250             final BigDecimal max) {
251         boolean check = false;
252         for (RangeConstraint r : parentRanges) {
253             Number parentMinNumber = r.getMin();
254             if (parentMinNumber instanceof UnknownBoundaryNumber) {
255                 parentMinNumber = resolveMinRange(parentMinNumber);
256             }
257             BigDecimal parentMin = new BigDecimal(parentMinNumber.toString());
258
259             Number parentMaxNumber = r.getMax();
260             if (parentMaxNumber instanceof UnknownBoundaryNumber) {
261                 parentMaxNumber = resolveMaxRange(parentMaxNumber);
262             }
263             BigDecimal parentMax = new BigDecimal(parentMaxNumber.toString());
264
265             if (parentMin.compareTo(min) <= 0 && parentMax.compareTo(max) >= 0) {
266                 check = true;
267                 break;
268             }
269         }
270         return check;
271     }
272
273     private void validateLength() {
274         validateLength(getLength());
275     }
276
277     private void validateLength(List<LengthConstraint> typeLength) {
278         if (lengths.size() < 2) {
279             return;
280         }
281
282         for (LengthConstraint length : typeLength) {
283             if (length.getMin() instanceof UnknownBoundaryNumber || length.getMax() instanceof UnknownBoundaryNumber) {
284                 throw new YangParseException(moduleName, line, "Unresolved length constraints");
285             }
286             final long min = length.getMin().longValue();
287             final long max = length.getMax().longValue();
288
289             List<LengthConstraint> parentLengths = lengths.get(1);
290             if (!areLengthRangesSubintervalsOfParentLengthRanges(parentLengths, min, max)) {
291                 throw new YangParseException(moduleName, line, "Invalid length constraint: <" + min + ", " + max
292                         + "> (parent: " + parentLengths + ").");
293             }
294         }
295     }
296
297     private boolean areLengthRangesSubintervalsOfParentLengthRanges(final List<LengthConstraint> parentLengths,
298             final long min, final long max) {
299         boolean check = false;
300         for (LengthConstraint lc : parentLengths) {
301             Number parentMinNumber = lc.getMin();
302             if (parentMinNumber instanceof UnknownBoundaryNumber) {
303                 parentMinNumber = resolveMinLength(parentMinNumber);
304             }
305             long parentMin = parentMinNumber.longValue();
306
307             Number parentMaxNumber = lc.getMax();
308             if (parentMaxNumber instanceof UnknownBoundaryNumber) {
309                 parentMaxNumber = resolveMaxLength(parentMaxNumber);
310             }
311             long parentMax = parentMaxNumber.longValue();
312
313             if (parentMin <= min && parentMax >= max) {
314                 check = true;
315                 break;
316             }
317         }
318         return check;
319     }
320
321 }