2 * Copyright (c) 2015 Pantheon Technologies s.r.o. 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.model.ri.type;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.base.Preconditions;
13 import com.google.common.base.Verify;
14 import com.google.common.collect.ImmutableRangeSet;
15 import com.google.common.collect.ImmutableRangeSet.Builder;
16 import com.google.common.collect.Range;
17 import com.google.common.collect.RangeSet;
18 import java.util.List;
19 import java.util.Optional;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.model.api.ConstraintMetaDefinition;
23 import org.opendaylight.yangtools.yang.model.api.stmt.UnresolvedNumber;
24 import org.opendaylight.yangtools.yang.model.api.stmt.ValueRange;
25 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
26 import org.opendaylight.yangtools.yang.model.api.type.LengthRestrictedTypeDefinition;
28 public abstract class LengthRestrictedTypeBuilder<T extends LengthRestrictedTypeDefinition<T>>
29 extends AbstractRestrictedTypeBuilder<T> {
30 private LengthConstraint lengthConstraint;
32 LengthRestrictedTypeBuilder(final T baseType, final QName qname) {
33 super(requireNonNull(baseType), qname);
37 * Set a new length constraint.
39 * @param constraint Constraint metadata
40 * @param ranges Allowed ranges
41 * @throws IllegalStateException if the constraint has already been set
42 * @throws InvalidLengthConstraintException if one of the proposed ranges does not overlap with supertype
43 * @throws NullPointerException if any of the arguments is null
45 public final void setLengthConstraint(final @NonNull ConstraintMetaDefinition constraint,
46 final @NonNull List<ValueRange> ranges) throws InvalidLengthConstraintException {
47 Preconditions.checkState(lengthConstraint == null, "Length constraint already defined as %s", lengthConstraint);
48 final LengthConstraint baseLengths = findLenghts();
49 if (ranges.isEmpty()) {
50 lengthConstraint = baseLengths;
54 // Run through alternatives and resolve them against the base type
55 requireNonNull(constraint);
56 final Builder<Integer> builder = ImmutableRangeSet.builder();
57 final Range<Integer> span = baseLengths.getAllowedRanges().span();
59 for (ValueRange c : ranges) {
60 builder.add(Range.closed(resolveLength(c.lowerBound(), span), resolveLength(c.upperBound(), span)));
64 // Now verify if new ranges are strict subset of base ranges
65 final RangeSet<Integer> allowed = builder.build();
66 final RangeSet<Integer> baseRanges = baseLengths.getAllowedRanges();
67 for (Range<Integer> range : allowed.asRanges()) {
68 if (!baseRanges.encloses(range)) {
69 throw new InvalidLengthConstraintException("Range %s is not a subset of parent constraint %s", range,
74 lengthConstraint = new ResolvedLengthConstraint(constraint, allowed);
78 abstract @NonNull T buildType(LengthConstraint constraint);
82 return buildType(lengthConstraint != null ? lengthConstraint : findLenghts());
85 abstract LengthConstraint typeLengthConstraints();
87 private static Integer resolveLength(final Number unresolved, final Range<Integer> span) {
88 if (unresolved instanceof Integer) {
89 return (Integer) unresolved;
91 if (unresolved instanceof UnresolvedNumber) {
92 return ((UnresolvedNumber)unresolved).resolveLength(span);
95 return Verify.verifyNotNull(NumberUtil.converterTo(Integer.class)).apply(unresolved);
98 private LengthConstraint findLenghts() {
99 Optional<LengthConstraint> ret = Optional.empty();
100 T wlk = getBaseType();
101 while (wlk != null && ret.isEmpty()) {
102 ret = wlk.getLengthConstraint();
103 wlk = wlk.getBaseType();
106 return ret.orElse(typeLengthConstraints());