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