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