BUG-8043: correct RangeConstraint definition
[yangtools.git] / yang / yang-model-util / src / main / java / org / opendaylight / yangtools / yang / model / util / type / CompatUtils.java
1 /*
2  * Copyright (c) 2015 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.model.util.type;
9
10 import com.google.common.base.Preconditions;
11 import java.util.List;
12 import java.util.Optional;
13 import javax.annotation.Nonnull;
14 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
15 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
16 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
17 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
18 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
19 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
20 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
21 import org.opendaylight.yangtools.yang.model.api.type.LengthRestrictedTypeDefinition;
22 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
23 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
24 import org.opendaylight.yangtools.yang.model.api.type.RangeRestrictedTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
27
28 /**
29  * Compatibility utilities for dealing with differences between the old parser's ExtendedType-driven type
30  * representation versus the representation this package models.
31  *
32  * @deprecated This class is provided strictly for compatibility only. No new users should be introduced, as this class
33  *             is scheduled for removal when its two OpenDaylight users, Java Binding v1 and YANG JMX Bindings are
34  *             removed.
35  */
36 @Deprecated
37 public final class CompatUtils {
38     private CompatUtils() {
39         throw new UnsupportedOperationException();
40     }
41
42     /**
43      * This package's type hierarchy model generates a type which encapsulates the default value and units for leaves.
44      * Java Binding specification is implemented in a way, where it needs to revert this process if the internal
45      * declaration has not restricted the type further -- which is not something available via
46      * {@link TypeDefinition#getBaseType()}.
47      *
48      * <p>
49      * Here are the possible scenarios:
50      *
51      * <pre>
52      * leaf foo {
53      *     type uint8 {
54      *         range 1..2;
55      *     }
56      * }
57      * </pre>
58      * The leaf type's schema path does not match the schema path of the leaf. We do NOT want to strip it, as
59      * we need to generate an inner class to hold the restrictions.
60      *
61      * <pre>
62      * leaf foo {
63      *     type uint8 {
64      *         range 1..2;
65      *     }
66      *     default 1;
67      * }
68      * </pre>
69      * The leaf type's schema path will match the schema path of the leaf. We do NOT want to strip it, as we need
70      * to generate an inner class to hold the restrictions.
71      *
72      * <pre>
73      * leaf foo {
74      *     type uint8;
75      *     default 1;
76      * }
77      * </pre>
78      * The leaf type's schema path will match the schema path of the leaf. We DO want to strip it, as we will deal
79      * with the default value ourselves.
80      *
81      * <pre>
82      * leaf foo {
83      *     type uint8;
84      * }
85      * </pre>
86      * The leaf type's schema path will not match the schema path of the leaf. We do NOT want to strip it.
87      *
88      * <p>
89      * The situation is different for types which do not have a default instantiation in YANG: leafref, enumeration,
90      * identityref, decimal64, bits and union. If these types are defined within this leaf's statement, a base type
91      * will be instantiated. If the leaf defines a default statement, this base type will be visible via getBaseType().
92      *
93      * <pre>
94      * leaf foo {
95      *     type decimal64 {
96      *         fraction-digits 2;
97      *     }
98      * }
99      * </pre>
100      * The leaf type's schema path will not match the schema path of the leaf, and we do not want to strip it, as it
101      * needs to be generated.
102      *
103      * <pre>
104      * leaf foo {
105      *     type decimal64 {
106      *         fraction-digits 2;
107      *     }
108      *     default 1;
109      * }
110      * </pre>
111      * The leaf type's schema path will match the schema path of the leaf, and we DO want to strip it.
112      *
113      * @param leaf Leaf for which we are acquiring the type
114      * @return Potentially base type of the leaf type.
115      */
116     @Nonnull public static TypeDefinition<?> compatLeafType(@Nonnull final LeafSchemaNode leaf) {
117         final TypeDefinition<?> leafType = leaf.getType();
118         Preconditions.checkNotNull(leafType);
119
120         if (!leaf.getPath().equals(leafType.getPath())) {
121             // Old parser semantics, or no new default/units defined for this leaf
122             return leafType;
123         }
124
125         // We are dealing with a type generated for the leaf itself
126         final TypeDefinition<?> baseType = leafType.getBaseType();
127         Preconditions.checkArgument(baseType != null, "Leaf %s has type for leaf, but no base type", leaf);
128
129         if (leaf.getPath().equals(baseType.getPath().getParent())) {
130             // Internal instantiation of a base YANG type (decimal64 and similar)
131             return baseType;
132         }
133
134         // At this point we have dealt with the easy cases. Now we need to perform per-type checking if there are no
135         // new constraints introduced by this type. If there were not, we will return the base type.
136         if (leafType instanceof BinaryTypeDefinition) {
137             return baseTypeIfNotConstrained((BinaryTypeDefinition) leafType);
138         } else if (leafType instanceof DecimalTypeDefinition) {
139             return baseTypeIfNotConstrained((DecimalTypeDefinition) leafType);
140         } else if (leafType instanceof InstanceIdentifierTypeDefinition) {
141             return baseTypeIfNotConstrained((InstanceIdentifierTypeDefinition) leafType);
142         } else if (leafType instanceof IntegerTypeDefinition) {
143             return baseTypeIfNotConstrained((IntegerTypeDefinition) leafType);
144         } else if (leafType instanceof StringTypeDefinition) {
145             return baseTypeIfNotConstrained((StringTypeDefinition) leafType);
146         } else if (leafType instanceof UnsignedIntegerTypeDefinition) {
147             return baseTypeIfNotConstrained((UnsignedIntegerTypeDefinition) leafType);
148         } else {
149             // Other types cannot be constrained, return the base type
150             return baseType;
151         }
152     }
153
154     private static BinaryTypeDefinition baseTypeIfNotConstrained(final BinaryTypeDefinition type) {
155         return baseTypeIfNotConstrained(type, type.getBaseType());
156     }
157
158     private static TypeDefinition<?> baseTypeIfNotConstrained(final DecimalTypeDefinition type) {
159         return baseTypeIfNotConstrained(type, type.getBaseType());
160     }
161
162     private static TypeDefinition<?> baseTypeIfNotConstrained(final InstanceIdentifierTypeDefinition type) {
163         final InstanceIdentifierTypeDefinition base = type.getBaseType();
164         return type.requireInstance() == base.requireInstance() ? base : type;
165     }
166
167     private static TypeDefinition<?> baseTypeIfNotConstrained(final IntegerTypeDefinition type) {
168         return baseTypeIfNotConstrained(type, type.getBaseType());
169     }
170
171     private static TypeDefinition<?> baseTypeIfNotConstrained(final StringTypeDefinition type) {
172         final StringTypeDefinition base = type.getBaseType();
173         final List<PatternConstraint> patterns = type.getPatternConstraints();
174         final Optional<LengthConstraint> optLengths = type.getLengthConstraint();
175
176         if ((patterns.isEmpty() || patterns.equals(base.getPatternConstraints()))
177                 && (!optLengths.isPresent() || optLengths.equals(base.getLengthConstraint()))) {
178             return base;
179         }
180
181         return type;
182     }
183
184     private static TypeDefinition<?> baseTypeIfNotConstrained(final UnsignedIntegerTypeDefinition type) {
185         return baseTypeIfNotConstrained(type, type.getBaseType());
186     }
187
188     private static <T extends RangeRestrictedTypeDefinition<T>> T baseTypeIfNotConstrained(final T type,
189             final T base) {
190         final Optional<RangeConstraint<?>> optConstraint = type.getRangeConstraint();
191         if (!optConstraint.isPresent()) {
192             return base;
193         }
194         return optConstraint.equals(base.getRangeConstraint()) ? base : type;
195     }
196
197     private static <T extends LengthRestrictedTypeDefinition<T>> T baseTypeIfNotConstrained(final T type,
198             final T base) {
199         final Optional<LengthConstraint> optConstraint = type.getLengthConstraint();
200         if (!optConstraint.isPresent()) {
201             return base;
202         }
203         return optConstraint.equals(base.getLengthConstraint()) ? base : type;
204     }
205 }