BUG-865: deprecate pre-Beryllium parser elements
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / builder / impl / TypeUtils.java
1 /*
2  * Copyright (c) 2013 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.parser.builder.impl;
9
10 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findBaseIdentity;
11 import java.net.URI;
12 import java.util.Date;
13 import java.util.Map;
14 import java.util.NavigableMap;
15 import java.util.Set;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
18 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
19 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
20 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
21 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
22 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
23 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
24 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
25 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
26 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
27 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
28 import org.opendaylight.yangtools.yang.parser.util.TypeConstraints;
29 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
30
31 /**
32  * Utility class which contains helper methods for dealing with type operations.
33  *
34  * @deprecated Pre-Beryllium implementation, scheduled for removal.
35  */
36 @Deprecated
37 public final class TypeUtils {
38
39     private TypeUtils() {
40     }
41
42     /**
43      * Resolve unknown type of node. It is assumed that type of node is either
44      * UnknownType or ExtendedType with UnknownType as base type.
45      *
46      * @param nodeToResolve
47      *            node with type to resolve
48      * @param modules
49      *            all loaded modules
50      * @param module
51      *            current module
52      */
53     public static void resolveType(final TypeAwareBuilder nodeToResolve,
54             final Map<URI, NavigableMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
55         QName unknownTypeQName = nodeToResolve.getTypeQName();
56         final ModuleBuilder dependentModuleBuilder = BuilderUtils.findModule(unknownTypeQName, modules);
57         if (dependentModuleBuilder == null) {
58             throw new YangParseException(module.getName(), nodeToResolve.getLine(), "Type not found: "
59                     + unknownTypeQName);
60         }
61         TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder, modules,
62                 module);
63         nodeToResolve.setTypedef(resolvedType);
64     }
65
66     /**
67      * Resolve union type which contains one or more unresolved types.
68      *
69      * @param union
70      *            union type builder to resolve
71      * @param modules
72      *            all loaded modules
73      * @param module
74      *            current module
75      */
76     public static void resolveTypeUnion(final UnionTypeBuilder union,
77             final Map<URI, NavigableMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
78         // special handling for identityref types under union
79         for (TypeDefinitionBuilder unionType : union.getTypedefs()) {
80             if (unionType instanceof IdentityrefTypeBuilder) {
81                 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) unionType;
82                 IdentitySchemaNodeBuilder identity = findBaseIdentity(module, idref.getBaseString(),
83                         idref.getLine());
84                 if (identity == null) {
85                     throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity");
86                 }
87                 idref.setBaseIdentity(identity);
88             }
89         }
90         for (QName unknownTypeQName : union.getBaseTypeQNames()) {
91             final ModuleBuilder dependentModuleBuilder = BuilderUtils.findModule(unknownTypeQName, modules);
92             if (dependentModuleBuilder == null) {
93                 throw new YangParseException(module.getName(), union.getLine(), "Type not found: " + unknownTypeQName);
94             }
95
96             final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModuleBuilder,
97                     unknownTypeQName.getLocalName(), module.getName(), union.getLine());
98             union.setTypedef(targetTypeBuilder);
99         }
100     }
101
102     /**
103      * Find type definition of type of unresolved node.
104      *
105      * @param nodeToResolve
106      *            node with unresolved type
107      * @param dependentModuleBuilder
108      *            module in which type definition is present
109      * @param modules
110      *            all loaded modules
111      * @param module
112      *            current module
113      * @return TypeDefinitionBuilder of node type
114      */
115     private static TypeDefinitionBuilder findUnknownTypeDefinition(final TypeAwareBuilder nodeToResolve,
116             final ModuleBuilder dependentModuleBuilder, final Map<URI, NavigableMap<Date, ModuleBuilder>> modules,
117             final ModuleBuilder module) {
118         final int line = nodeToResolve.getLine();
119         final QName unknownTypeQName = nodeToResolve.getTypeQName();
120         final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
121                 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
122
123         // validate constraints
124         final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
125                 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module);
126         constraints.validateConstraints();
127
128         return targetTypeBuilder;
129     }
130
131     /**
132      * Search types for type with given name.
133      *
134      * @param types
135      *            types to search
136      * @param name
137      *            name of type
138      * @return type with given name if present in collection, null otherwise
139      */
140     private static TypeDefinitionBuilder findTypedefBuilderByName(final Set<TypeDefinitionBuilder> types, final String name) {
141         for (TypeDefinitionBuilder td : types) {
142             if (td.getQName().getLocalName().equals(name)) {
143                 return td;
144             }
145         }
146         return null;
147     }
148
149     /**
150      * Pull restriction from type and add them to constraints.
151      *
152      * @param type
153      *            type from which constraints will be read
154      * @param constraints
155      *            constraints object to which constraints will be added
156      */
157     private static TypeConstraints mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
158         if (type instanceof DecimalTypeDefinition) {
159             constraints.addRanges(((DecimalTypeDefinition) type).getRangeConstraints());
160             constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
161         } else if (type instanceof IntegerTypeDefinition) {
162             constraints.addRanges(((IntegerTypeDefinition) type).getRangeConstraints());
163         } else if (type instanceof UnsignedIntegerTypeDefinition) {
164             constraints.addRanges(((UnsignedIntegerTypeDefinition) type).getRangeConstraints());
165         } else if (type instanceof StringTypeDefinition) {
166             constraints.addPatterns(((StringTypeDefinition) type).getPatternConstraints());
167             constraints.addLengths(((StringTypeDefinition) type).getLengthConstraints());
168         } else if (type instanceof BinaryTypeDefinition) {
169             constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
170         } else if (type instanceof ExtendedType) {
171             constraints.addFractionDigits(((ExtendedType) type).getFractionDigits());
172             constraints.addLengths(((ExtendedType) type).getLengthConstraints());
173             constraints.addPatterns(((ExtendedType) type).getPatternConstraints());
174             constraints.addRanges(((ExtendedType) type).getRangeConstraints());
175         }
176         return constraints;
177     }
178
179     private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
180             final TypeConstraints constraints, final Map<URI, NavigableMap<Date, ModuleBuilder>> modules,
181             final ModuleBuilder builder) {
182
183         // union and identityref types cannot be restricted
184         if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
185             return constraints;
186         }
187
188         if (nodeToResolve instanceof TypeDefinitionBuilder) {
189             TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
190             constraints.addFractionDigits(typedefToResolve.getFractionDigits());
191             constraints.addLengths(typedefToResolve.getLengths());
192             constraints.addPatterns(typedefToResolve.getPatterns());
193             constraints.addRanges(typedefToResolve.getRanges());
194         }
195
196         TypeDefinition<?> type = nodeToResolve.getType();
197         if (type == null) {
198             final QName unknownTypeQName = nodeToResolve.getTypeQName();
199             if (unknownTypeQName == null) {
200                 return constraints;
201             }
202             final ModuleBuilder dependentModuleBuilder = BuilderUtils.findModule(unknownTypeQName, modules);
203             final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
204                     dependentModuleBuilder, unknownTypeQName.getLocalName(), builder.getName(), 0);
205             return findConstraintsFromTypeBuilder(targetTypeBuilder, constraints, modules, dependentModuleBuilder);
206         } else {
207             if (type instanceof ExtendedType) {
208                 mergeConstraints(type, constraints);
209                 // it has to be base yang type
210                 return mergeConstraints(type, constraints);
211             } else {
212                 // it is base yang type
213                 return mergeConstraints(type, constraints);
214             }
215         }
216     }
217
218     /**
219      * Search for type definition builder by name.
220      *
221      * @param nodeToResolve
222      *            node which contains unresolved type
223      * @param dependentModule
224      *            module which should contains referenced type
225      * @param typeName
226      *            name of type definition
227      * @param currentModuleName
228      *            name of current module
229      * @param line
230      *            current line in module
231      * @return typeDefinitionBuilder
232      */
233     private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
234             final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
235         Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
236         TypeDefinitionBuilder result = findTypedefBuilderByName(typedefs, typeName);
237         if (result != null) {
238             return result;
239         }
240
241         Builder parent = nodeToResolve.getParent();
242         while (parent != null) {
243             if (parent instanceof DataNodeContainerBuilder) {
244                 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
245             } else if (parent instanceof RpcDefinitionBuilder) {
246                 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
247             }
248             result = findTypedefBuilderByName(typedefs, typeName);
249             if (result == null) {
250                 parent = parent.getParent();
251             } else {
252                 break;
253             }
254         }
255
256         if (result == null) {
257             throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");
258         }
259         return result;
260     }
261
262 }