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.findModuleFromBuilders;
11 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.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.*;
22 import org.opendaylight.yangtools.yang.parser.util.TypeConstraints;
23 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
26 * Utility class which contains helper methods for dealing with type operations.
28 public final class TypeUtils {
34 * Resolve unknown type of node. It is assumed that type of node is either
35 * UnknownType or ExtendedType with UnknownType as base type.
37 * @param nodeToResolve
38 * node with type to resolve
44 public static void resolveType(final TypeAwareBuilder nodeToResolve,
45 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
46 final int line = nodeToResolve.getLine();
47 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
48 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
49 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
50 unknownTypeQName.getPrefix(), line);
52 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder, modules,
54 nodeToResolve.setTypedef(resolvedType);
58 * Resolve unknown type of node. It is assumed that type of node is either
59 * UnknownType or ExtendedType with UnknownType as base type.
61 * @param nodeToResolve
62 * node with type to resolve
68 * SchemaContext containing already resolved modules
70 public static void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
71 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
72 final SchemaContext context) {
73 final int line = nodeToResolve.getLine();
74 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
75 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
76 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
77 unknownTypeQName.getPrefix(), line);
79 if (dependentModuleBuilder == null) {
80 final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
81 final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
82 final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
84 if (nodeToResolveType instanceof ExtendedType) {
85 final ExtendedType extType = (ExtendedType) nodeToResolveType;
86 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module,
87 nodeToResolve.getLine());
89 nodeToResolve.setTypedef(newType);
91 if (nodeToResolve instanceof TypeDefinitionBuilder) {
92 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
93 TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
94 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
95 tdb.setLengths(tc.getLength());
96 tdb.setPatterns(tc.getPatterns());
97 tdb.setRanges(tc.getRange());
98 tdb.setFractionDigits(tc.getFractionDigits());
100 nodeToResolve.setType(type);
104 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder,
106 nodeToResolve.setTypedef(resolvedType);
110 public static void resolveTypeUnion(final UnionTypeBuilder union,
111 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
112 final List<TypeDefinition<?>> unionTypes = union.getTypes();
113 final List<TypeDefinition<?>> toRemove = new ArrayList<>();
114 for (TypeDefinition<?> unionType : unionTypes) {
115 if (unionType instanceof UnknownType) {
116 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, builder, unionType.getQName()
117 .getPrefix(), union.getLine());
118 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, unionType
119 .getQName().getLocalName(), builder.getName(), union.getLine());
120 union.setTypedef(resolvedType);
121 toRemove.add(unionType);
122 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
123 final UnknownType ut = (UnknownType) unionType.getBaseType();
124 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, builder, ut.getQName()
125 .getPrefix(), union.getLine());
126 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule, ut
127 .getQName().getLocalName(), builder.getName(), union.getLine());
128 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null,
129 (ExtendedType) unionType, modules, builder, union.getLine());
130 union.setTypedef(newType);
131 toRemove.add(unionType);
134 unionTypes.removeAll(toRemove);
138 * Resolve union type which contains one or more unresolved types.
141 * union type builder to resolve
147 * SchemaContext containing already resolved modules
149 public static void resolveTypeUnionWithContext(final UnionTypeBuilder union,
150 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
151 final SchemaContext context) {
152 final List<TypeDefinition<?>> unionTypes = union.getTypes();
153 final List<TypeDefinition<?>> toRemove = new ArrayList<>();
154 for (TypeDefinition<?> unionType : unionTypes) {
155 if (unionType instanceof UnknownType) {
156 resolveUnionUnknownType(union, (UnknownType) unionType, modules, module, context);
157 toRemove.add(unionType);
158 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
159 resolveUnionUnknownType(union, (ExtendedType) unionType, modules, module, context);
160 toRemove.add(unionType);
163 unionTypes.removeAll(toRemove);
166 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final UnknownType ut,
167 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
168 final SchemaContext context) {
169 final int line = union.getLine();
170 final QName utQName = ut.getQName();
171 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, utQName.getPrefix(), line);
173 if (dependentModuleBuilder == null) {
174 Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(), line);
175 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
176 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
179 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
180 utQName.getLocalName(), module.getName(), union.getLine());
181 union.setTypedef(resolvedType);
185 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final ExtendedType extType,
186 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
187 final SchemaContext context) {
188 final int line = union.getLine();
189 final TypeDefinition<?> extTypeBase = extType.getBaseType();
190 final UnknownType ut = (UnknownType) extTypeBase;
191 final QName utQName = ut.getQName();
192 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, utQName.getPrefix(), line);
194 if (dependentModuleBuilder == null) {
195 final Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(), line);
196 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
197 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
198 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module, 0);
199 union.setTypedef(newType);
201 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModuleBuilder,
202 utQName.getLocalName(), module.getName(), line);
203 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules,
205 union.setTypedef(newType);
210 * Find type definition of type of unresolved node.
212 * @param nodeToResolve
213 * node with unresolved type
214 * @param dependentModuleBuilder
215 * module in which type definition is present
220 * @return TypeDefinitionBuilder of node type
222 private static TypeDefinitionBuilder findUnknownTypeDefinition(final TypeAwareBuilder nodeToResolve,
223 final ModuleBuilder dependentModuleBuilder, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
224 final ModuleBuilder module) {
225 final int line = nodeToResolve.getLine();
226 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
227 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
228 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
229 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
231 TypeDefinitionBuilder resolvedType;
232 if (nodeToResolveType instanceof ExtendedType) {
233 final ExtendedType extType = (ExtendedType) nodeToResolveType;
234 resolvedType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules, module,
235 nodeToResolve.getLine());
237 resolvedType = targetTypeBuilder;
240 // validate constraints
241 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
242 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
243 constraints.validateConstraints();
249 * Search types for type with given name.
255 * @return type with given name if present in collection, null otherwise
257 private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
258 for (TypeDefinitionBuilder td : types) {
259 if (td.getQName().getLocalName().equals(name)) {
270 * collection of types
273 * @return type with given name if it is present in collection, null
276 private static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
277 for (TypeDefinition<?> type : types) {
278 if (type.getQName().getLocalName().equals(typeName)) {
286 * Pull restriction from type and add them to constraints.
289 * type from which constraints will be read
291 * constraints object to which constraints will be added
293 private static TypeConstraints mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
294 if (type instanceof DecimalTypeDefinition) {
295 constraints.addRanges(((DecimalTypeDefinition) type).getRangeConstraints());
296 constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
297 } else if (type instanceof IntegerTypeDefinition) {
298 constraints.addRanges(((IntegerTypeDefinition) type).getRangeConstraints());
299 } else if (type instanceof UnsignedIntegerTypeDefinition) {
300 constraints.addRanges(((UnsignedIntegerTypeDefinition) type).getRangeConstraints());
301 } else if (type instanceof StringTypeDefinition) {
302 constraints.addPatterns(((StringTypeDefinition) type).getPatternConstraints());
303 constraints.addLengths(((StringTypeDefinition) type).getLengthConstraints());
304 } else if (type instanceof BinaryTypeDefinition) {
305 constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
306 } else if (type instanceof ExtendedType) {
307 constraints.addFractionDigits(((ExtendedType) type).getFractionDigits());
308 constraints.addLengths(((ExtendedType) type).getLengthConstraints());
309 constraints.addPatterns(((ExtendedType) type).getPatternConstraints());
310 constraints.addRanges(((ExtendedType) type).getRangeConstraints());
316 * Create new type builder based on old type with new base type. Note: only
317 * one of newBaseTypeBuilder or newBaseType can be specified.
319 * @param newBaseTypeBuilder
320 * new base type builder or null
322 * new base type or null
323 * @param oldExtendedType
330 * current line in module
331 * @return new type builder based on old type with new base type
333 private static TypeDefinitionBuilder extendedTypeWithNewBase(final TypeDefinitionBuilder newBaseTypeBuilder,
334 final TypeDefinition<?> newBaseType, final ExtendedType oldExtendedType,
335 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module, final int line) {
336 if ((newBaseTypeBuilder == null && newBaseType == null) || (newBaseTypeBuilder != null && newBaseType != null)) {
337 throw new YangParseException(module.getName(), line,
338 "only one of newBaseTypeBuilder or newBaseType can be specified");
341 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
342 oldExtendedType.getQName(), oldExtendedType.getPath());
343 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
344 TypeConstraints constraints;
345 if (newBaseType == null) {
346 tc.addFractionDigits(oldExtendedType.getFractionDigits());
347 tc.addLengths(oldExtendedType.getLengthConstraints());
348 tc.addPatterns(oldExtendedType.getPatternConstraints());
349 tc.addRanges(oldExtendedType.getRangeConstraints());
350 constraints = findConstraintsFromTypeBuilder(newBaseTypeBuilder, tc, modules, module, null);
351 newType.setTypedef(newBaseTypeBuilder);
353 constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
354 newType.setType(newBaseType);
357 newType.setDescription(oldExtendedType.getDescription());
358 newType.setReference(oldExtendedType.getReference());
359 newType.setStatus(oldExtendedType.getStatus());
360 newType.setLengths(constraints.getLength());
361 newType.setPatterns(constraints.getPatterns());
362 newType.setRanges(constraints.getRange());
363 newType.setFractionDigits(constraints.getFractionDigits());
364 newType.setUnits(oldExtendedType.getUnits());
365 newType.setDefaultValue(oldExtendedType.getDefaultValue());
370 * Pull restrictions from type and add them to constraints.
372 * @param typeToResolve
373 * type from which constraints will be read
375 * constraints object to which constraints will be added
376 * @return constraints contstraints object containing constraints from given
379 private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
380 final TypeConstraints constraints) {
381 // union type cannot be restricted
382 if (typeToResolve instanceof UnionTypeDefinition) {
385 if (typeToResolve instanceof ExtendedType) {
386 ExtendedType extType = (ExtendedType) typeToResolve;
387 constraints.addFractionDigits(extType.getFractionDigits());
388 constraints.addLengths(extType.getLengthConstraints());
389 constraints.addPatterns(extType.getPatternConstraints());
390 constraints.addRanges(extType.getRangeConstraints());
391 return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
393 mergeConstraints(typeToResolve, constraints);
398 private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
399 final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
400 final ModuleBuilder builder, final SchemaContext context) {
402 // union and identityref types cannot be restricted
403 if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
407 if (nodeToResolve instanceof TypeDefinitionBuilder) {
408 TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
409 constraints.addFractionDigits(typedefToResolve.getFractionDigits());
410 constraints.addLengths(typedefToResolve.getLengths());
411 constraints.addPatterns(typedefToResolve.getPatterns());
412 constraints.addRanges(typedefToResolve.getRanges());
415 TypeDefinition<?> type = nodeToResolve.getType();
417 return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
419 QName qname = type.getQName();
420 if (type instanceof UnknownType) {
421 ModuleBuilder dependentModuleBuilder = BuilderUtils.findModuleFromBuilders(modules, builder,
422 qname.getPrefix(), nodeToResolve.getLine());
423 if (dependentModuleBuilder == null) {
424 if (context == null) {
425 throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
426 "Failed to resolved type constraints.");
428 Module dm = BuilderUtils.findModuleFromContext(context, builder, qname.getPrefix(),
429 nodeToResolve.getLine());
430 TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
431 return mergeConstraints(t, constraints);
434 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
435 qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
436 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
438 } else if (type instanceof ExtendedType) {
439 mergeConstraints(type, constraints);
441 TypeDefinition<?> base = ((ExtendedType) type).getBaseType();
442 if (base instanceof UnknownType) {
443 ModuleBuilder dependentModule = BuilderUtils.findModuleFromBuilders(modules, builder, base
444 .getQName().getPrefix(), nodeToResolve.getLine());
445 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
446 .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
447 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
449 // it has to be base yang type
450 return mergeConstraints(type, constraints);
453 // it is base yang type
454 return mergeConstraints(type, constraints);
460 * Search for type definition builder by name.
462 * @param nodeToResolve
463 * node which contains unresolved type
464 * @param dependentModule
465 * module which should contains referenced type
467 * name of type definition
468 * @param currentModuleName
469 * name of current module
471 * current line in module
472 * @return typeDefinitionBuilder
474 private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
475 final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
476 Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
477 TypeDefinitionBuilder result = findTypedefBuilderByName(typedefs, typeName);
478 if (result != null) {
482 Builder parent = nodeToResolve.getParent();
483 while (parent != null) {
484 if (parent instanceof DataNodeContainerBuilder) {
485 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
486 } else if (parent instanceof RpcDefinitionBuilder) {
487 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
489 result = findTypedefBuilderByName(typedefs, typeName);
490 if (result == null) {
491 parent = parent.getParent();
497 if (result == null) {
498 throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");