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.util;
10 import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.findModuleFromBuilders;
11 import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.findModuleFromContext;
15 import org.opendaylight.yangtools.yang.common.QName;
16 import org.opendaylight.yangtools.yang.model.api.*;
17 import org.opendaylight.yangtools.yang.model.api.type.*;
18 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
19 import org.opendaylight.yangtools.yang.model.util.UnknownType;
20 import org.opendaylight.yangtools.yang.parser.builder.api.*;
21 import org.opendaylight.yangtools.yang.parser.builder.impl.*;
24 * Utility class which contains helper methods for dealing with type operations.
26 public final class TypeUtils {
32 * Resolve unknown type of node. It is assumed that type of node is either
33 * UnknownType or ExtendedType with UnknownType as base type.
35 * @param nodeToResolve
36 * node with type to resolve
42 public static void resolveType(final TypeAwareBuilder nodeToResolve,
43 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
44 final int line = nodeToResolve.getLine();
45 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
46 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
47 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
48 unknownTypeQName.getPrefix(), line);
50 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder, modules,
52 nodeToResolve.setTypedef(resolvedType);
56 * Resolve unknown type of node. It is assumed that type of node is either
57 * UnknownType or ExtendedType with UnknownType as base type.
59 * @param nodeToResolve
60 * node with type to resolve
66 * SchemaContext containing already resolved modules
68 public static void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
69 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
70 final SchemaContext context) {
71 final int line = nodeToResolve.getLine();
72 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
73 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
74 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
75 unknownTypeQName.getPrefix(), line);
77 if (dependentModuleBuilder == null) {
78 final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
79 final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
80 final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
82 if (nodeToResolveType instanceof ExtendedType) {
83 final ExtendedType extType = (ExtendedType) nodeToResolveType;
84 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module,
85 nodeToResolve.getLine());
87 nodeToResolve.setTypedef(newType);
89 if (nodeToResolve instanceof TypeDefinitionBuilder) {
90 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
91 TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
92 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
93 tdb.setLengths(tc.getLength());
94 tdb.setPatterns(tc.getPatterns());
95 tdb.setRanges(tc.getRange());
96 tdb.setFractionDigits(tc.getFractionDigits());
98 nodeToResolve.setType(type);
102 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder,
104 nodeToResolve.setTypedef(resolvedType);
108 public static void resolveTypeUnion(final UnionTypeBuilder union,
109 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
110 final List<TypeDefinition<?>> unionTypes = union.getTypes();
111 final List<TypeDefinition<?>> toRemove = new ArrayList<>();
112 for (TypeDefinition<?> unionType : unionTypes) {
113 if (unionType instanceof UnknownType) {
114 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, builder, unionType.getQName()
115 .getPrefix(), union.getLine());
116 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, unionType
117 .getQName().getLocalName(), builder.getName(), union.getLine());
118 union.setTypedef(resolvedType);
119 toRemove.add(unionType);
120 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
121 final UnknownType ut = (UnknownType) unionType.getBaseType();
122 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, builder, ut.getQName()
123 .getPrefix(), union.getLine());
124 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule, ut
125 .getQName().getLocalName(), builder.getName(), union.getLine());
126 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null,
127 (ExtendedType) unionType, modules, builder, union.getLine());
128 union.setTypedef(newType);
129 toRemove.add(unionType);
132 unionTypes.removeAll(toRemove);
136 * Resolve union type which contains one or more unresolved types.
139 * union type builder to resolve
145 * SchemaContext containing already resolved modules
147 public static void resolveTypeUnionWithContext(final UnionTypeBuilder union,
148 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
149 final SchemaContext context) {
150 final List<TypeDefinition<?>> unionTypes = union.getTypes();
151 final List<TypeDefinition<?>> toRemove = new ArrayList<>();
152 for (TypeDefinition<?> unionType : unionTypes) {
153 if (unionType instanceof UnknownType) {
154 resolveUnionUnknownType(union, (UnknownType) unionType, modules, module, context);
155 toRemove.add(unionType);
156 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
157 resolveUnionUnknownType(union, (ExtendedType) unionType, modules, module, context);
158 toRemove.add(unionType);
161 unionTypes.removeAll(toRemove);
164 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final UnknownType ut,
165 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
166 final SchemaContext context) {
167 final int line = union.getLine();
168 final QName utQName = ut.getQName();
169 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, utQName.getPrefix(), line);
171 if (dependentModuleBuilder == null) {
172 Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(), line);
173 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
174 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
177 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
178 utQName.getLocalName(), module.getName(), union.getLine());
179 union.setTypedef(resolvedType);
183 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final ExtendedType extType,
184 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
185 final SchemaContext context) {
186 final int line = union.getLine();
187 final TypeDefinition<?> extTypeBase = extType.getBaseType();
188 final UnknownType ut = (UnknownType) extTypeBase;
189 final QName utQName = ut.getQName();
190 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, utQName.getPrefix(), line);
192 if (dependentModuleBuilder == null) {
193 final Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(), line);
194 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
195 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
196 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module, 0);
197 union.setTypedef(newType);
199 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModuleBuilder,
200 utQName.getLocalName(), module.getName(), line);
201 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules,
203 union.setTypedef(newType);
208 * Find type definition of type of unresolved node.
210 * @param nodeToResolve
211 * node with unresolved type
212 * @param dependentModuleBuilder
213 * module in which type definition is present
218 * @return TypeDefinitionBuilder of node type
220 private static TypeDefinitionBuilder findUnknownTypeDefinition(final TypeAwareBuilder nodeToResolve,
221 final ModuleBuilder dependentModuleBuilder, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
222 final ModuleBuilder module) {
223 final int line = nodeToResolve.getLine();
224 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
225 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
226 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
227 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
229 TypeDefinitionBuilder resolvedType;
230 if (nodeToResolveType instanceof ExtendedType) {
231 final ExtendedType extType = (ExtendedType) nodeToResolveType;
232 resolvedType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules, module,
233 nodeToResolve.getLine());
235 resolvedType = targetTypeBuilder;
238 // validate constraints
239 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
240 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
241 constraints.validateConstraints();
247 * Search types for type with given name.
253 * @return type with given name if present in collection, null otherwise
255 private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
256 for (TypeDefinitionBuilder td : types) {
257 if (td.getQName().getLocalName().equals(name)) {
268 * collection of types
271 * @return type with given name if it is present in collection, null
274 private static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
275 for (TypeDefinition<?> type : types) {
276 if (type.getQName().getLocalName().equals(typeName)) {
284 * Pull restriction from type and add them to constraints.
287 * type from which constraints will be read
289 * constraints object to which constraints will be added
291 private static TypeConstraints mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
292 if (type instanceof DecimalTypeDefinition) {
293 constraints.addRanges(((DecimalTypeDefinition) type).getRangeConstraints());
294 constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
295 } else if (type instanceof IntegerTypeDefinition) {
296 constraints.addRanges(((IntegerTypeDefinition) type).getRangeConstraints());
297 } else if (type instanceof UnsignedIntegerTypeDefinition) {
298 constraints.addRanges(((UnsignedIntegerTypeDefinition) type).getRangeConstraints());
299 } else if (type instanceof StringTypeDefinition) {
300 constraints.addPatterns(((StringTypeDefinition) type).getPatternConstraints());
301 constraints.addLengths(((StringTypeDefinition) type).getLengthConstraints());
302 } else if (type instanceof BinaryTypeDefinition) {
303 constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
304 } else if (type instanceof ExtendedType) {
305 constraints.addFractionDigits(((ExtendedType) type).getFractionDigits());
306 constraints.addLengths(((ExtendedType) type).getLengthConstraints());
307 constraints.addPatterns(((ExtendedType) type).getPatternConstraints());
308 constraints.addRanges(((ExtendedType) type).getRangeConstraints());
314 * Create new type builder based on old type with new base type. Note: only
315 * one of newBaseTypeBuilder or newBaseType can be specified.
317 * @param newBaseTypeBuilder
318 * new base type builder or null
320 * new base type or null
321 * @param oldExtendedType
328 * current line in module
329 * @return new type builder based on old type with new base type
331 private static TypeDefinitionBuilder extendedTypeWithNewBase(final TypeDefinitionBuilder newBaseTypeBuilder,
332 final TypeDefinition<?> newBaseType, final ExtendedType oldExtendedType,
333 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module, final int line) {
334 if ((newBaseTypeBuilder == null && newBaseType == null) || (newBaseTypeBuilder != null && newBaseType != null)) {
335 throw new YangParseException(module.getName(), line,
336 "only one of newBaseTypeBuilder or newBaseType can be specified");
339 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
340 oldExtendedType.getQName(), oldExtendedType.getPath());
341 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
342 TypeConstraints constraints;
343 if (newBaseType == null) {
344 tc.addFractionDigits(oldExtendedType.getFractionDigits());
345 tc.addLengths(oldExtendedType.getLengthConstraints());
346 tc.addPatterns(oldExtendedType.getPatternConstraints());
347 tc.addRanges(oldExtendedType.getRangeConstraints());
348 constraints = findConstraintsFromTypeBuilder(newBaseTypeBuilder, tc, modules, module, null);
349 newType.setTypedef(newBaseTypeBuilder);
351 constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
352 newType.setType(newBaseType);
355 newType.setDescription(oldExtendedType.getDescription());
356 newType.setReference(oldExtendedType.getReference());
357 newType.setStatus(oldExtendedType.getStatus());
358 newType.setLengths(constraints.getLength());
359 newType.setPatterns(constraints.getPatterns());
360 newType.setRanges(constraints.getRange());
361 newType.setFractionDigits(constraints.getFractionDigits());
362 newType.setUnits(oldExtendedType.getUnits());
363 newType.setDefaultValue(oldExtendedType.getDefaultValue());
368 * Pull restrictions from type and add them to constraints.
370 * @param typeToResolve
371 * type from which constraints will be read
373 * constraints object to which constraints will be added
374 * @return constraints contstraints object containing constraints from given
377 private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
378 final TypeConstraints constraints) {
379 // union type cannot be restricted
380 if (typeToResolve instanceof UnionTypeDefinition) {
383 if (typeToResolve instanceof ExtendedType) {
384 ExtendedType extType = (ExtendedType) typeToResolve;
385 constraints.addFractionDigits(extType.getFractionDigits());
386 constraints.addLengths(extType.getLengthConstraints());
387 constraints.addPatterns(extType.getPatternConstraints());
388 constraints.addRanges(extType.getRangeConstraints());
389 return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
391 mergeConstraints(typeToResolve, constraints);
396 private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
397 final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
398 final ModuleBuilder builder, final SchemaContext context) {
400 // union and identityref types cannot be restricted
401 if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
405 if (nodeToResolve instanceof TypeDefinitionBuilder) {
406 TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
407 constraints.addFractionDigits(typedefToResolve.getFractionDigits());
408 constraints.addLengths(typedefToResolve.getLengths());
409 constraints.addPatterns(typedefToResolve.getPatterns());
410 constraints.addRanges(typedefToResolve.getRanges());
413 TypeDefinition<?> type = nodeToResolve.getType();
415 return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
417 QName qname = type.getQName();
418 if (type instanceof UnknownType) {
419 ModuleBuilder dependentModuleBuilder = ParserUtils.findModuleFromBuilders(modules, builder,
420 qname.getPrefix(), nodeToResolve.getLine());
421 if (dependentModuleBuilder == null) {
422 if (context == null) {
423 throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
424 "Failed to resolved type constraints.");
426 Module dm = ParserUtils.findModuleFromContext(context, builder, qname.getPrefix(),
427 nodeToResolve.getLine());
428 TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
429 return mergeConstraints(t, constraints);
432 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
433 qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
434 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
436 } else if (type instanceof ExtendedType) {
437 mergeConstraints(type, constraints);
439 TypeDefinition<?> base = ((ExtendedType) type).getBaseType();
440 if (base instanceof UnknownType) {
441 ModuleBuilder dependentModule = ParserUtils.findModuleFromBuilders(modules, builder, base
442 .getQName().getPrefix(), nodeToResolve.getLine());
443 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
444 .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
445 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
447 // it has to be base yang type
448 return mergeConstraints(type, constraints);
451 // it is base yang type
452 return mergeConstraints(type, constraints);
458 * Search for type definition builder by name.
460 * @param nodeToResolve
461 * node which contains unresolved type
462 * @param dependentModule
463 * module which should contains referenced type
465 * name of type definition
466 * @param currentModuleName
467 * name of current module
469 * current line in module
470 * @return typeDefinitionBuilder
472 private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
473 final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
474 Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
475 TypeDefinitionBuilder result = findTypedefBuilderByName(typedefs, typeName);
476 if (result != null) {
480 Builder parent = nodeToResolve.getParent();
481 while (parent != null) {
482 if (parent instanceof DataNodeContainerBuilder) {
483 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
484 } else if (parent instanceof RpcDefinitionBuilder) {
485 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
487 result = findTypedefBuilderByName(typedefs, typeName);
488 if (result == null) {
489 parent = parent.getParent();
495 if (result == null) {
496 throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");