2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.util;
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;
20 * Holder object for holding YANG type constraints.
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<>();
30 public TypeConstraints(final String moduleName, final int line) {
31 this.moduleName = moduleName;
35 public List<RangeConstraint> getRange() {
36 if (ranges.size() < 2) {
37 return Collections.emptyList();
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();
46 if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
47 if (ranges.size() > 1) {
48 validateRange(resolved);
53 if (firstRange.equals(lastRange)) {
54 if (min instanceof UnknownBoundaryNumber) {
55 min = resolveMinRange(min);
57 if (max instanceof UnknownBoundaryNumber) {
58 max = resolveMaxRange(max);
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);
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);
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);
79 if (this.ranges.size() > 1) {
80 validateRange(resolved);
85 private Number resolveMinRange(final Number min) {
88 while (newMin instanceof UnknownBoundaryNumber) {
89 final List<RangeConstraint> act = ranges.get(i);
90 newMin = act.get(0).getMin();
96 private Number resolveMaxRange(final Number max) {
99 while (newMax instanceof UnknownBoundaryNumber) {
100 final List<RangeConstraint> act = ranges.get(i);
101 newMax = act.get(act.size() - 1).getMax();
107 public void addRanges(final List<RangeConstraint> ranges) {
108 if (ranges != null && !(ranges.isEmpty())) {
109 this.ranges.add(ranges);
113 public List<List<LengthConstraint>> getAllLengths() {
117 public List<LengthConstraint> getLength() {
118 if (lengths.size() < 2) {
119 return Collections.emptyList();
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();
128 if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
129 if (lengths.size() > 1) {
130 validateLength(resolved);
135 if (firstLength.equals(lastLength)) {
136 if (min instanceof UnknownBoundaryNumber) {
137 min = resolveMinLength(min);
139 if (max instanceof UnknownBoundaryNumber) {
140 max = resolveMaxLength(max);
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);
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);
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);
163 if (lengths.size() > 1) {
164 validateLength(resolved);
169 private Number resolveMinLength(final Number min) {
172 while (newMin instanceof UnknownBoundaryNumber) {
173 final List<LengthConstraint> act = lengths.get(i);
174 newMin = act.get(0).getMin();
180 private Number resolveMaxLength(final Number max) {
183 while (newMax instanceof UnknownBoundaryNumber) {
184 final List<LengthConstraint> act = lengths.get(i);
185 newMax = act.get(act.size() - 1).getMax();
191 public void addLengths(final List<LengthConstraint> lengths) {
192 if (lengths != null && !(lengths.isEmpty())) {
193 this.lengths.add(lengths);
197 public List<PatternConstraint> getPatterns() {
198 if (patterns.isEmpty()) {
199 return Collections.emptyList();
201 return patterns.get(0);
204 public void addPatterns(final List<PatternConstraint> patterns) {
205 this.patterns.add(patterns);
208 public Integer getFractionDigits() {
209 if (fractionDigits.isEmpty()) {
212 return fractionDigits.get(0);
215 public void addFractionDigits(final Integer fractionDigits) {
216 this.fractionDigits.add(fractionDigits);
219 public void validateConstraints() {
224 private void validateRange() {
225 validateRange(getRange());
228 private void validateRange(List<RangeConstraint> typeRange) {
229 if (ranges.size() < 2) {
233 for (RangeConstraint range : typeRange) {
234 if (range.getMin() instanceof UnknownBoundaryNumber || range.getMax() instanceof UnknownBoundaryNumber) {
235 throw new YangParseException(moduleName, line, "Unresolved range constraints");
237 final BigDecimal min = new BigDecimal(range.getMin().toString());
238 final BigDecimal max = new BigDecimal(range.getMax().toString());
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 + ").");
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);
256 BigDecimal parentMin = new BigDecimal(parentMinNumber.toString());
258 Number parentMaxNumber = r.getMax();
259 if (parentMaxNumber instanceof UnknownBoundaryNumber) {
260 parentMaxNumber = resolveMaxRange(parentMaxNumber);
262 BigDecimal parentMax = new BigDecimal(parentMaxNumber.toString());
264 if (parentMin.compareTo(min) <= 0 && parentMax.compareTo(max) >= 0) {
272 private void validateLength() {
273 validateLength(getLength());
276 private void validateLength(List<LengthConstraint> typeLength) {
277 if (lengths.size() < 2) {
281 for (LengthConstraint length : typeLength) {
282 if (length.getMin() instanceof UnknownBoundaryNumber || length.getMax() instanceof UnknownBoundaryNumber) {
283 throw new YangParseException(moduleName, line, "Unresolved length constraints");
285 final long min = length.getMin().longValue();
286 final long max = length.getMax().longValue();
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 + ").");
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);
304 long parentMin = parentMinNumber.longValue();
306 Number parentMaxNumber = lc.getMax();
307 if (parentMaxNumber instanceof UnknownBoundaryNumber) {
308 parentMaxNumber = resolveMaxLength(parentMaxNumber);
310 long parentMax = parentMaxNumber.longValue();
312 if (parentMin <= min && parentMax >= max) {