2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.builder.impl;
10 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findBaseIdentity;
12 import java.util.ArrayList;
13 import java.util.Date;
14 import java.util.List;
17 import java.util.TreeMap;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
20 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
21 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
22 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
27 import org.opendaylight.yangtools.yang.model.util.UnknownType;
28 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
29 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
30 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
31 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
32 import org.opendaylight.yangtools.yang.parser.util.TypeConstraints;
33 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
36 * Utility class which contains helper methods for dealing with type operations.
38 public final class TypeUtils {
44 * Resolve unknown type of node. It is assumed that type of node is either
45 * UnknownType or ExtendedType with UnknownType as base type.
47 * @param nodeToResolve
48 * node with type to resolve
54 public static void resolveType(final TypeAwareBuilder nodeToResolve,
55 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
56 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
57 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
58 final ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(module, unknownTypeQName.getPrefix());
59 if (dependentModuleBuilder == null) {
60 throw new YangParseException(module.getName(), nodeToResolve.getLine(), "No module found for import "
61 + unknownTypeQName.getPrefix());
63 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder, modules,
65 nodeToResolve.setTypedef(resolvedType);
69 * Resolve union type which contains one or more unresolved types.
72 * union type builder to resolve
78 public static void resolveTypeUnion(final UnionTypeBuilder union,
79 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
80 final List<TypeDefinition<?>> unionTypes = union.getTypes();
81 final List<TypeDefinition<?>> toRemove = new ArrayList<>();
82 for (TypeDefinition<?> unionType : unionTypes) {
83 if (unionType instanceof UnknownType) {
84 resolveUnionUnknownType(union, (UnknownType) unionType, modules, module);
85 toRemove.add(unionType);
86 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
87 resolveUnionUnknownType(union, (ExtendedType) unionType, modules, module);
88 toRemove.add(unionType);
91 // special handling for identityref types under union
92 for (TypeDefinitionBuilder unionType : union.getTypedefs()) {
93 if (unionType instanceof IdentityrefTypeBuilder) {
94 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) unionType;
95 IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
97 if (identity == null) {
98 throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity");
100 idref.setBaseIdentity(identity);
103 unionTypes.removeAll(toRemove);
106 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final UnknownType ut,
107 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
108 final QName utQName = ut.getQName();
109 final ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(module, utQName.getPrefix());
110 if (dependentModuleBuilder == null) {
111 throw new YangParseException(module.getName(), union.getLine(), "No module found with prefix "
112 + utQName.getPrefix());
114 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
115 utQName.getLocalName(), module.getName(), union.getLine());
116 union.setTypedef(resolvedType);
119 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final ExtendedType extType,
120 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
121 final int line = union.getLine();
122 final TypeDefinition<?> extTypeBase = extType.getBaseType();
123 final UnknownType ut = (UnknownType) extTypeBase;
124 final QName utQName = ut.getQName();
125 final ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(module, utQName.getPrefix());
126 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModuleBuilder,
127 utQName.getLocalName(), module.getName(), line);
128 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules,
130 union.setTypedef(newType);
134 * Find type definition of type of unresolved node.
136 * @param nodeToResolve
137 * node with unresolved type
138 * @param dependentModuleBuilder
139 * module in which type definition is present
144 * @return TypeDefinitionBuilder of node type
146 private static TypeDefinitionBuilder findUnknownTypeDefinition(final TypeAwareBuilder nodeToResolve,
147 final ModuleBuilder dependentModuleBuilder, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
148 final ModuleBuilder module) {
149 final int line = nodeToResolve.getLine();
150 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
151 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
152 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
153 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
155 TypeDefinitionBuilder resolvedType;
156 if (nodeToResolveType instanceof ExtendedType) {
157 final ExtendedType extType = (ExtendedType) nodeToResolveType;
158 resolvedType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules, module,
159 nodeToResolve.getLine());
161 resolvedType = targetTypeBuilder;
164 // validate constraints
165 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
166 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module);
167 constraints.validateConstraints();
173 * Search types for type with given name.
179 * @return type with given name if present in collection, null otherwise
181 private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
182 for (TypeDefinitionBuilder td : types) {
183 if (td.getQName().getLocalName().equals(name)) {
191 * Pull restriction from type and add them to constraints.
194 * type from which constraints will be read
196 * constraints object to which constraints will be added
198 private static TypeConstraints mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
199 if (type instanceof DecimalTypeDefinition) {
200 constraints.addRanges(((DecimalTypeDefinition) type).getRangeConstraints());
201 constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
202 } else if (type instanceof IntegerTypeDefinition) {
203 constraints.addRanges(((IntegerTypeDefinition) type).getRangeConstraints());
204 } else if (type instanceof UnsignedIntegerTypeDefinition) {
205 constraints.addRanges(((UnsignedIntegerTypeDefinition) type).getRangeConstraints());
206 } else if (type instanceof StringTypeDefinition) {
207 constraints.addPatterns(((StringTypeDefinition) type).getPatternConstraints());
208 constraints.addLengths(((StringTypeDefinition) type).getLengthConstraints());
209 } else if (type instanceof BinaryTypeDefinition) {
210 constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
211 } else if (type instanceof ExtendedType) {
212 constraints.addFractionDigits(((ExtendedType) type).getFractionDigits());
213 constraints.addLengths(((ExtendedType) type).getLengthConstraints());
214 constraints.addPatterns(((ExtendedType) type).getPatternConstraints());
215 constraints.addRanges(((ExtendedType) type).getRangeConstraints());
221 * Create new type builder based on old type with new base type. Note: only
222 * one of newBaseTypeBuilder or newBaseType can be specified.
224 * @param newBaseTypeBuilder
225 * new base type builder or null
227 * new base type or null
228 * @param oldExtendedType
235 * current line in module
236 * @return new type builder based on old type with new base type
238 private static TypeDefinitionBuilder extendedTypeWithNewBase(final TypeDefinitionBuilder newBaseTypeBuilder,
239 final TypeDefinition<?> newBaseType, final ExtendedType oldExtendedType,
240 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module, final int line) {
241 if ((newBaseTypeBuilder == null && newBaseType == null) || (newBaseTypeBuilder != null && newBaseType != null)) {
242 throw new YangParseException(module.getName(), line,
243 "only one of newBaseTypeBuilder or newBaseType can be specified");
246 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
247 oldExtendedType.getQName(), oldExtendedType.getPath());
248 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
249 TypeConstraints constraints;
250 if (newBaseType == null) {
251 tc.addFractionDigits(oldExtendedType.getFractionDigits());
252 tc.addLengths(oldExtendedType.getLengthConstraints());
253 tc.addPatterns(oldExtendedType.getPatternConstraints());
254 tc.addRanges(oldExtendedType.getRangeConstraints());
255 constraints = findConstraintsFromTypeBuilder(newBaseTypeBuilder, tc, modules, module);
256 newType.setTypedef(newBaseTypeBuilder);
258 constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
259 newType.setType(newBaseType);
262 newType.setDescription(oldExtendedType.getDescription());
263 newType.setReference(oldExtendedType.getReference());
264 newType.setStatus(oldExtendedType.getStatus());
265 newType.setLengths(constraints.getLength());
266 newType.setPatterns(constraints.getPatterns());
267 newType.setRanges(constraints.getRange());
268 newType.setFractionDigits(constraints.getFractionDigits());
269 newType.setUnits(oldExtendedType.getUnits());
270 newType.setDefaultValue(oldExtendedType.getDefaultValue());
275 * Pull restrictions from type and add them to constraints.
277 * @param typeToResolve
278 * type from which constraints will be read
280 * constraints object to which constraints will be added
281 * @return constraints contstraints object containing constraints from given
284 private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
285 final TypeConstraints constraints) {
286 // union type cannot be restricted
287 if (typeToResolve instanceof UnionTypeDefinition) {
290 if (typeToResolve instanceof ExtendedType) {
291 ExtendedType extType = (ExtendedType) typeToResolve;
292 constraints.addFractionDigits(extType.getFractionDigits());
293 constraints.addLengths(extType.getLengthConstraints());
294 constraints.addPatterns(extType.getPatternConstraints());
295 constraints.addRanges(extType.getRangeConstraints());
296 return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
298 mergeConstraints(typeToResolve, constraints);
303 private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
304 final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
305 final ModuleBuilder builder) {
307 // union and identityref types cannot be restricted
308 if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
312 if (nodeToResolve instanceof TypeDefinitionBuilder) {
313 TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
314 constraints.addFractionDigits(typedefToResolve.getFractionDigits());
315 constraints.addLengths(typedefToResolve.getLengths());
316 constraints.addPatterns(typedefToResolve.getPatterns());
317 constraints.addRanges(typedefToResolve.getRanges());
320 TypeDefinition<?> type = nodeToResolve.getType();
322 return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder);
324 QName qname = type.getQName();
325 if (type instanceof UnknownType) {
326 ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(builder, qname.getPrefix());
327 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
328 qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
329 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder);
330 } else if (type instanceof ExtendedType) {
331 mergeConstraints(type, constraints);
333 TypeDefinition<?> base = ((ExtendedType) type).getBaseType();
334 if (base instanceof UnknownType) {
335 ModuleBuilder dependentModule = BuilderUtils.getModuleByPrefix(builder, base.getQName().getPrefix());
336 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
337 .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
338 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule);
340 // it has to be base yang type
341 return mergeConstraints(type, constraints);
344 // it is base yang type
345 return mergeConstraints(type, constraints);
351 * Search for type definition builder by name.
353 * @param nodeToResolve
354 * node which contains unresolved type
355 * @param dependentModule
356 * module which should contains referenced type
358 * name of type definition
359 * @param currentModuleName
360 * name of current module
362 * current line in module
363 * @return typeDefinitionBuilder
365 private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
366 final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
367 Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
368 TypeDefinitionBuilder result = findTypedefBuilderByName(typedefs, typeName);
369 if (result != null) {
373 Builder parent = nodeToResolve.getParent();
374 while (parent != null) {
375 if (parent instanceof DataNodeContainerBuilder) {
376 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
377 } else if (parent instanceof RpcDefinitionBuilder) {
378 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
380 result = findTypedefBuilderByName(typedefs, typeName);
381 if (result == null) {
382 parent = parent.getParent();
388 if (result == null) {
389 throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");