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;
13 import java.util.ArrayList;
14 import java.util.Date;
15 import java.util.List;
18 import java.util.TreeMap;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.model.api.Module;
22 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
23 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
28 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
30 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
31 import org.opendaylight.yangtools.yang.model.util.UnknownType;
32 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
33 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
34 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
35 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
36 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
37 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
38 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
39 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
40 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
43 * Utility class which contains helper methods for dealing with type operations.
45 public final class TypeUtils {
51 * Resolve unknown type of node. It is assumed that type of node is either
52 * UnknownType or ExtendedType with UnknownType as base type.
54 * @param nodeToResolve
55 * node with type to resolve
61 public static void resolveType(final TypeAwareBuilder nodeToResolve,
62 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
63 final int line = nodeToResolve.getLine();
64 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
65 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
66 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
67 unknownTypeQName.getPrefix(), line);
69 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder, modules,
71 nodeToResolve.setTypedef(resolvedType);
75 * Resolve unknown type of node. It is assumed that type of node is either
76 * UnknownType or ExtendedType with UnknownType as base type.
78 * @param nodeToResolve
79 * node with type to resolve
85 * SchemaContext containing already resolved modules
87 public static void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
88 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
89 final SchemaContext context) {
90 final int line = nodeToResolve.getLine();
91 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
92 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
93 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
94 unknownTypeQName.getPrefix(), line);
96 if (dependentModuleBuilder == null) {
97 final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
98 final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
99 final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
101 if (nodeToResolveType instanceof ExtendedType) {
102 final ExtendedType extType = (ExtendedType) nodeToResolveType;
103 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module,
104 nodeToResolve.getLine());
106 nodeToResolve.setTypedef(newType);
108 if (nodeToResolve instanceof TypeDefinitionBuilder) {
109 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
110 TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
111 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
112 tdb.setLengths(tc.getLength());
113 tdb.setPatterns(tc.getPatterns());
114 tdb.setRanges(tc.getRange());
115 tdb.setFractionDigits(tc.getFractionDigits());
117 nodeToResolve.setType(type);
121 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder,
123 nodeToResolve.setTypedef(resolvedType);
127 public static void resolveTypeUnion(final UnionTypeBuilder union,
128 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
129 final List<TypeDefinition<?>> unionTypes = union.getTypes();
130 final List<TypeDefinition<?>> toRemove = new ArrayList<>();
131 for (TypeDefinition<?> unionType : unionTypes) {
132 if (unionType instanceof UnknownType) {
133 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, builder, unionType.getQName()
134 .getPrefix(), union.getLine());
135 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, unionType
136 .getQName().getLocalName(), builder.getName(), union.getLine());
137 union.setTypedef(resolvedType);
138 toRemove.add(unionType);
139 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
140 final UnknownType ut = (UnknownType) unionType.getBaseType();
141 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, builder, ut.getQName()
142 .getPrefix(), union.getLine());
143 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule, ut
144 .getQName().getLocalName(), builder.getName(), union.getLine());
145 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null,
146 (ExtendedType) unionType, modules, builder, union.getLine());
147 union.setTypedef(newType);
148 toRemove.add(unionType);
151 unionTypes.removeAll(toRemove);
155 * Resolve union type which contains one or more unresolved types.
158 * union type builder to resolve
164 * SchemaContext containing already resolved modules
166 public static void resolveTypeUnionWithContext(final UnionTypeBuilder union,
167 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
168 final SchemaContext context) {
169 final List<TypeDefinition<?>> unionTypes = union.getTypes();
170 final List<TypeDefinition<?>> toRemove = new ArrayList<>();
171 for (TypeDefinition<?> unionType : unionTypes) {
172 if (unionType instanceof UnknownType) {
173 resolveUnionUnknownType(union, (UnknownType) unionType, modules, module, context);
174 toRemove.add(unionType);
175 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
176 resolveUnionUnknownType(union, (ExtendedType) unionType, modules, module, context);
177 toRemove.add(unionType);
180 unionTypes.removeAll(toRemove);
183 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final UnknownType ut,
184 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
185 final SchemaContext context) {
186 final int line = union.getLine();
187 final QName utQName = ut.getQName();
188 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, utQName.getPrefix(), line);
190 if (dependentModuleBuilder == null) {
191 Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(), line);
192 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
193 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
196 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
197 utQName.getLocalName(), module.getName(), union.getLine());
198 union.setTypedef(resolvedType);
202 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final ExtendedType extType,
203 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
204 final SchemaContext context) {
205 final int line = union.getLine();
206 final TypeDefinition<?> extTypeBase = extType.getBaseType();
207 final UnknownType ut = (UnknownType) extTypeBase;
208 final QName utQName = ut.getQName();
209 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, utQName.getPrefix(), line);
211 if (dependentModuleBuilder == null) {
212 final Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(), line);
213 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
214 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
215 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module, 0);
216 union.setTypedef(newType);
218 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModuleBuilder,
219 utQName.getLocalName(), module.getName(), line);
220 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules,
222 union.setTypedef(newType);
227 * Find type definition of type of unresolved node.
229 * @param nodeToResolve
230 * node with unresolved type
231 * @param dependentModuleBuilder
232 * module in which type definition is present
237 * @return TypeDefinitionBuilder of node type
239 private static TypeDefinitionBuilder findUnknownTypeDefinition(final TypeAwareBuilder nodeToResolve,
240 final ModuleBuilder dependentModuleBuilder, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
241 final ModuleBuilder module) {
242 final int line = nodeToResolve.getLine();
243 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
244 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
245 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
246 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
248 TypeDefinitionBuilder resolvedType;
249 if (nodeToResolveType instanceof ExtendedType) {
250 final ExtendedType extType = (ExtendedType) nodeToResolveType;
251 resolvedType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules, module,
252 nodeToResolve.getLine());
254 resolvedType = targetTypeBuilder;
257 // validate constraints
258 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
259 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
260 constraints.validateConstraints();
266 * Search types for type with given name.
272 * @return type with given name if present in collection, null otherwise
274 private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
275 for (TypeDefinitionBuilder td : types) {
276 if (td.getQName().getLocalName().equals(name)) {
287 * collection of types
290 * @return type with given name if it is present in collection, null
293 private static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
294 for (TypeDefinition<?> type : types) {
295 if (type.getQName().getLocalName().equals(typeName)) {
303 * Pull restriction from type and add them to constraints.
306 * type from which constraints will be read
308 * constraints object to which constraints will be added
310 private static TypeConstraints mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
311 if (type instanceof DecimalTypeDefinition) {
312 constraints.addRanges(((DecimalTypeDefinition) type).getRangeConstraints());
313 constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
314 } else if (type instanceof IntegerTypeDefinition) {
315 constraints.addRanges(((IntegerTypeDefinition) type).getRangeConstraints());
316 } else if (type instanceof UnsignedIntegerTypeDefinition) {
317 constraints.addRanges(((UnsignedIntegerTypeDefinition) type).getRangeConstraints());
318 } else if (type instanceof StringTypeDefinition) {
319 constraints.addPatterns(((StringTypeDefinition) type).getPatternConstraints());
320 constraints.addLengths(((StringTypeDefinition) type).getLengthConstraints());
321 } else if (type instanceof BinaryTypeDefinition) {
322 constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
323 } else if (type instanceof ExtendedType) {
324 constraints.addFractionDigits(((ExtendedType) type).getFractionDigits());
325 constraints.addLengths(((ExtendedType) type).getLengthConstraints());
326 constraints.addPatterns(((ExtendedType) type).getPatternConstraints());
327 constraints.addRanges(((ExtendedType) type).getRangeConstraints());
333 * Create new type builder based on old type with new base type. Note: only
334 * one of newBaseTypeBuilder or newBaseType can be specified.
336 * @param newBaseTypeBuilder
337 * new base type builder or null
339 * new base type or null
340 * @param oldExtendedType
347 * current line in module
348 * @return new type builder based on old type with new base type
350 private static TypeDefinitionBuilder extendedTypeWithNewBase(final TypeDefinitionBuilder newBaseTypeBuilder,
351 final TypeDefinition<?> newBaseType, final ExtendedType oldExtendedType,
352 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module, final int line) {
353 if ((newBaseTypeBuilder == null && newBaseType == null) || (newBaseTypeBuilder != null && newBaseType != null)) {
354 throw new YangParseException(module.getName(), line,
355 "only one of newBaseTypeBuilder or newBaseType can be specified");
358 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
359 oldExtendedType.getQName());
360 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
361 TypeConstraints constraints;
362 if (newBaseType == null) {
363 tc.addFractionDigits(oldExtendedType.getFractionDigits());
364 tc.addLengths(oldExtendedType.getLengthConstraints());
365 tc.addPatterns(oldExtendedType.getPatternConstraints());
366 tc.addRanges(oldExtendedType.getRangeConstraints());
367 constraints = findConstraintsFromTypeBuilder(newBaseTypeBuilder, tc, modules, module, null);
368 newType.setTypedef(newBaseTypeBuilder);
370 constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
371 newType.setType(newBaseType);
374 newType.setPath(oldExtendedType.getPath());
375 newType.setDescription(oldExtendedType.getDescription());
376 newType.setReference(oldExtendedType.getReference());
377 newType.setStatus(oldExtendedType.getStatus());
378 newType.setLengths(constraints.getLength());
379 newType.setPatterns(constraints.getPatterns());
380 newType.setRanges(constraints.getRange());
381 newType.setFractionDigits(constraints.getFractionDigits());
382 newType.setUnits(oldExtendedType.getUnits());
383 newType.setDefaultValue(oldExtendedType.getDefaultValue());
384 newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
389 * Pull restrictions from type and add them to constraints.
391 * @param typeToResolve
392 * type from which constraints will be read
394 * constraints object to which constraints will be added
395 * @return constraints contstraints object containing constraints from given
398 private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
399 final TypeConstraints constraints) {
400 // union type cannot be restricted
401 if (typeToResolve instanceof UnionTypeDefinition) {
404 if (typeToResolve instanceof ExtendedType) {
405 ExtendedType extType = (ExtendedType) typeToResolve;
406 constraints.addFractionDigits(extType.getFractionDigits());
407 constraints.addLengths(extType.getLengthConstraints());
408 constraints.addPatterns(extType.getPatternConstraints());
409 constraints.addRanges(extType.getRangeConstraints());
410 return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
412 mergeConstraints(typeToResolve, constraints);
417 private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
418 final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
419 final ModuleBuilder builder, final SchemaContext context) {
421 // union and identityref types cannot be restricted
422 if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
426 if (nodeToResolve instanceof TypeDefinitionBuilder) {
427 TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
428 constraints.addFractionDigits(typedefToResolve.getFractionDigits());
429 constraints.addLengths(typedefToResolve.getLengths());
430 constraints.addPatterns(typedefToResolve.getPatterns());
431 constraints.addRanges(typedefToResolve.getRanges());
434 TypeDefinition<?> type = nodeToResolve.getType();
436 return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
438 QName qname = type.getQName();
439 if (type instanceof UnknownType) {
440 ModuleBuilder dependentModuleBuilder = ParserUtils.findModuleFromBuilders(modules, builder,
441 qname.getPrefix(), nodeToResolve.getLine());
442 if (dependentModuleBuilder == null) {
443 if (context == null) {
444 throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
445 "Failed to resolved type constraints.");
447 Module dm = ParserUtils.findModuleFromContext(context, builder, qname.getPrefix(),
448 nodeToResolve.getLine());
449 TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
450 return mergeConstraints(t, constraints);
453 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
454 qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
455 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
457 } else if (type instanceof ExtendedType) {
458 mergeConstraints(type, constraints);
460 TypeDefinition<?> base = ((ExtendedType) type).getBaseType();
461 if (base instanceof UnknownType) {
462 ModuleBuilder dependentModule = ParserUtils.findModuleFromBuilders(modules, builder, base
463 .getQName().getPrefix(), nodeToResolve.getLine());
464 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
465 .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
466 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
468 // it has to be base yang type
469 return mergeConstraints(type, constraints);
472 // it is base yang type
473 return mergeConstraints(type, constraints);
479 * Search for type definition builder by name.
481 * @param nodeToResolve
482 * node which contains unresolved type
483 * @param dependentModule
484 * module which should contains referenced type
486 * name of type definition
487 * @param currentModuleName
488 * name of current module
490 * current line in module
491 * @return typeDefinitionBuilder
493 private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
494 final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
495 Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
496 TypeDefinitionBuilder result = findTypedefBuilderByName(typedefs, typeName);
497 if (result != null) {
501 Builder parent = nodeToResolve.getParent();
502 while (parent != null) {
503 if (parent instanceof DataNodeContainerBuilder) {
504 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
505 } else if (parent instanceof RpcDefinitionBuilder) {
506 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
508 result = findTypedefBuilderByName(typedefs, typeName);
509 if (result == null) {
510 parent = parent.getParent();
516 if (result == null) {
517 throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");