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