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;
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;
21 * Holder object for holding YANG type constraints.
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<>();
31 public TypeConstraints(final String moduleName, final int line) {
32 this.moduleName = moduleName;
36 public List<RangeConstraint> getRange() {
37 if (ranges.size() < 2) {
38 return Collections.emptyList();
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();
47 if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
48 if (ranges.size() > 1) {
49 validateRange(resolved);
54 if (firstRange.equals(lastRange)) {
55 if (min instanceof UnknownBoundaryNumber) {
56 min = resolveMinRange(min);
58 if (max instanceof UnknownBoundaryNumber) {
59 max = resolveMaxRange(max);
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);
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);
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);
80 if (this.ranges.size() > 1) {
81 validateRange(resolved);
86 private Number resolveMinRange(final Number min) {
89 while (newMin instanceof UnknownBoundaryNumber) {
90 final List<RangeConstraint> act = ranges.get(i);
91 newMin = act.get(0).getMin();
97 private Number resolveMaxRange(final Number max) {
100 while (newMax instanceof UnknownBoundaryNumber) {
101 final List<RangeConstraint> act = ranges.get(i);
102 newMax = act.get(act.size() - 1).getMax();
108 public void addRanges(final List<RangeConstraint> ranges) {
109 if (ranges != null && !(ranges.isEmpty())) {
110 this.ranges.add(ranges);
114 public List<List<LengthConstraint>> getAllLengths() {
118 public List<LengthConstraint> getLength() {
119 if (lengths.size() < 2) {
120 return Collections.emptyList();
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();
129 if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
130 if (lengths.size() > 1) {
131 validateLength(resolved);
136 if (firstLength.equals(lastLength)) {
137 if (min instanceof UnknownBoundaryNumber) {
138 min = resolveMinLength(min);
140 if (max instanceof UnknownBoundaryNumber) {
141 max = resolveMaxLength(max);
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);
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);
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);
164 if (lengths.size() > 1) {
165 validateLength(resolved);
170 private Number resolveMinLength(final Number min) {
173 while (newMin instanceof UnknownBoundaryNumber) {
174 final List<LengthConstraint> act = lengths.get(i);
175 newMin = act.get(0).getMin();
181 private Number resolveMaxLength(final Number max) {
184 while (newMax instanceof UnknownBoundaryNumber) {
185 final List<LengthConstraint> act = lengths.get(i);
186 newMax = act.get(act.size() - 1).getMax();
192 public void addLengths(final List<LengthConstraint> lengths) {
193 if (lengths != null && !(lengths.isEmpty())) {
194 this.lengths.add(lengths);
198 public List<PatternConstraint> getPatterns() {
199 if (patterns.isEmpty()) {
200 return Collections.emptyList();
202 return patterns.get(0);
205 public void addPatterns(final List<PatternConstraint> patterns) {
206 this.patterns.add(patterns);
209 public Integer getFractionDigits() {
210 if (fractionDigits.isEmpty()) {
213 return fractionDigits.get(0);
216 public void addFractionDigits(final Integer fractionDigits) {
217 this.fractionDigits.add(fractionDigits);
220 public void validateConstraints() {
225 private void validateRange() {
226 validateRange(getRange());
229 private void validateRange(List<RangeConstraint> typeRange) {
230 if (ranges.size() < 2) {
234 for (RangeConstraint range : typeRange) {
235 if (range.getMin() instanceof UnknownBoundaryNumber || range.getMax() instanceof UnknownBoundaryNumber) {
236 throw new YangParseException(moduleName, line, "Unresolved range constraints");
238 final BigDecimal min = new BigDecimal(range.getMin().toString());
239 final BigDecimal max = new BigDecimal(range.getMax().toString());
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 + ").");
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);
257 BigDecimal parentMin = new BigDecimal(parentMinNumber.toString());
259 Number parentMaxNumber = r.getMax();
260 if (parentMaxNumber instanceof UnknownBoundaryNumber) {
261 parentMaxNumber = resolveMaxRange(parentMaxNumber);
263 BigDecimal parentMax = new BigDecimal(parentMaxNumber.toString());
265 if (parentMin.compareTo(min) <= 0 && parentMax.compareTo(max) >= 0) {
273 private void validateLength() {
274 validateLength(getLength());
277 private void validateLength(List<LengthConstraint> typeLength) {
278 if (lengths.size() < 2) {
282 for (LengthConstraint length : typeLength) {
283 if (length.getMin() instanceof UnknownBoundaryNumber || length.getMax() instanceof UnknownBoundaryNumber) {
284 throw new YangParseException(moduleName, line, "Unresolved length constraints");
286 final long min = length.getMin().longValue();
287 final long max = length.getMax().longValue();
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 + ").");
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);
305 long parentMin = parentMinNumber.longValue();
307 Number parentMaxNumber = lc.getMax();
308 if (parentMaxNumber instanceof UnknownBoundaryNumber) {
309 parentMaxNumber = resolveMaxLength(parentMaxNumber);
311 long parentMax = parentMaxNumber.longValue();
313 if (parentMin <= min && parentMax >= max) {