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.*;
12 import java.util.ArrayList;
13 import java.util.Date;
14 import java.util.List;
17 import java.util.TreeMap;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.Module;
21 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
22 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.type.*;
24 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
25 import org.opendaylight.yangtools.yang.model.util.UnknownType;
26 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
27 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
28 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
29 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
30 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
31 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
32 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
33 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
34 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
37 * Utility class which contains helper methods for dealing with type operations.
39 public final class TypeUtils {
45 * Resolve unknown type of node. It is assumed that type of node is either
46 * UnknownType or ExtendedType with UnknownType as base type.
48 * @param nodeToResolve
49 * node with type to resolve
55 public static void resolveType(final TypeAwareBuilder nodeToResolve,
56 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
57 final int line = nodeToResolve.getLine();
58 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
59 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
60 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
61 unknownTypeQName.getPrefix(), line);
63 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder, modules,
65 nodeToResolve.setTypedef(resolvedType);
69 * Resolve unknown type of node. It is assumed that type of node is either
70 * UnknownType or ExtendedType with UnknownType as base type.
72 * @param nodeToResolve
73 * node with type to resolve
79 * SchemaContext containing already resolved modules
81 public static void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
82 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
83 final SchemaContext context) {
84 final int line = nodeToResolve.getLine();
85 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
86 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
87 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
88 unknownTypeQName.getPrefix(), line);
90 if (dependentModuleBuilder == null) {
91 final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
92 final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
93 final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
95 if (nodeToResolveType instanceof ExtendedType) {
96 final ExtendedType extType = (ExtendedType) nodeToResolveType;
97 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module,
98 nodeToResolve.getLine());
100 nodeToResolve.setTypedef(newType);
102 if (nodeToResolve instanceof TypeDefinitionBuilder) {
103 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
104 TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
105 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
106 tdb.setLengths(tc.getLength());
107 tdb.setPatterns(tc.getPatterns());
108 tdb.setRanges(tc.getRange());
109 tdb.setFractionDigits(tc.getFractionDigits());
111 nodeToResolve.setType(type);
115 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder,
117 nodeToResolve.setTypedef(resolvedType);
121 public static void resolveTypeUnion(final UnionTypeBuilder union,
122 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
123 final List<TypeDefinition<?>> unionTypes = union.getTypes();
124 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
125 for (TypeDefinition<?> unionType : unionTypes) {
126 if (unionType instanceof UnknownType) {
127 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, builder, unionType.getQName()
128 .getPrefix(), union.getLine());
129 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, unionType
130 .getQName().getLocalName(), builder.getName(), union.getLine());
131 union.setTypedef(resolvedType);
132 toRemove.add(unionType);
133 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
134 final UnknownType ut = (UnknownType) unionType.getBaseType();
135 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, builder, ut.getQName()
136 .getPrefix(), union.getLine());
137 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule, ut
138 .getQName().getLocalName(), builder.getName(), union.getLine());
139 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null,
140 (ExtendedType) unionType, modules, builder, union.getLine());
141 union.setTypedef(newType);
142 toRemove.add(unionType);
145 unionTypes.removeAll(toRemove);
149 * Resolve union type which contains one or more unresolved types.
152 * union type builder to resolve
158 * SchemaContext containing already resolved modules
160 public static void resolveTypeUnionWithContext(final UnionTypeBuilder union,
161 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
162 final SchemaContext context) {
163 final List<TypeDefinition<?>> unionTypes = union.getTypes();
164 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
165 for (TypeDefinition<?> unionType : unionTypes) {
166 if (unionType instanceof UnknownType) {
167 resolveUnionUnknownType(union, (UnknownType) unionType, modules, module, context);
168 toRemove.add(unionType);
169 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
170 resolveUnionUnknownType(union, (ExtendedType) unionType, modules, module, context);
171 toRemove.add(unionType);
174 unionTypes.removeAll(toRemove);
177 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final UnknownType ut,
178 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
179 final SchemaContext context) {
180 final int line = union.getLine();
181 final QName utQName = ut.getQName();
182 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, utQName.getPrefix(), line);
184 if (dependentModuleBuilder == null) {
185 Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(), line);
186 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
187 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
190 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
191 utQName.getLocalName(), module.getName(), union.getLine());
192 union.setTypedef(resolvedType);
196 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final ExtendedType extType,
197 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
198 final SchemaContext context) {
199 final int line = union.getLine();
200 final TypeDefinition<?> extTypeBase = extType.getBaseType();
201 final UnknownType ut = (UnknownType) extTypeBase;
202 final QName utQName = ut.getQName();
203 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, utQName.getPrefix(), line);
205 if (dependentModuleBuilder == null) {
206 final Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(), line);
207 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
208 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
209 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module, 0);
210 union.setTypedef(newType);
212 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModuleBuilder,
213 utQName.getLocalName(), module.getName(), line);
214 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules,
216 union.setTypedef(newType);
221 * Find type definition of type of unresolved node.
223 * @param nodeToResolve
224 * node with unresolved type
225 * @param dependentModuleBuilder
226 * module in which type definition is present
231 * @return TypeDefinitionBuilder of node type
233 private static TypeDefinitionBuilder findUnknownTypeDefinition(final TypeAwareBuilder nodeToResolve,
234 final ModuleBuilder dependentModuleBuilder, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
235 final ModuleBuilder module) {
236 final int line = nodeToResolve.getLine();
237 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
238 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
239 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
240 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
242 TypeDefinitionBuilder resolvedType;
243 if (nodeToResolveType instanceof ExtendedType) {
244 final ExtendedType extType = (ExtendedType) nodeToResolveType;
245 resolvedType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules, module,
246 nodeToResolve.getLine());
248 resolvedType = targetTypeBuilder;
251 // validate constraints
252 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
253 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
254 constraints.validateConstraints();
260 * Search types for type with given name.
266 * @return type with given name if present in collection, null otherwise
268 private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
269 for (TypeDefinitionBuilder td : types) {
270 if (td.getQName().getLocalName().equals(name)) {
281 * collection of types
284 * @return type with given name if it is present in collection, null
287 private static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
288 for (TypeDefinition<?> type : types) {
289 if (type.getQName().getLocalName().equals(typeName)) {
297 * Pull restriction from type and add them to constraints.
300 * type from which constraints will be read
302 * constraints object to which constraints will be added
304 private static TypeConstraints mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
305 if (type instanceof DecimalTypeDefinition) {
306 constraints.addRanges(((DecimalTypeDefinition) type).getRangeConstraints());
307 constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
308 } else if (type instanceof IntegerTypeDefinition) {
309 constraints.addRanges(((IntegerTypeDefinition) type).getRangeConstraints());
310 } else if (type instanceof UnsignedIntegerTypeDefinition) {
311 constraints.addRanges(((UnsignedIntegerTypeDefinition) type).getRangeConstraints());
312 } else if (type instanceof StringTypeDefinition) {
313 constraints.addPatterns(((StringTypeDefinition) type).getPatternConstraints());
314 constraints.addLengths(((StringTypeDefinition) type).getLengthConstraints());
315 } else if (type instanceof BinaryTypeDefinition) {
316 constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
317 } else if (type instanceof ExtendedType) {
318 constraints.addFractionDigits(((ExtendedType) type).getFractionDigits());
319 constraints.addLengths(((ExtendedType) type).getLengthConstraints());
320 constraints.addPatterns(((ExtendedType) type).getPatternConstraints());
321 constraints.addRanges(((ExtendedType) type).getRangeConstraints());
327 * Create new type builder based on old type with new base type. Note: only
328 * one of newBaseTypeBuilder or newBaseType can be specified.
330 * @param newBaseTypeBuilder
331 * new base type builder or null
333 * new base type or null
334 * @param oldExtendedType
341 * current line in module
342 * @return new type builder based on old type with new base type
344 private static TypeDefinitionBuilder extendedTypeWithNewBase(final TypeDefinitionBuilder newBaseTypeBuilder,
345 final TypeDefinition<?> newBaseType, final ExtendedType oldExtendedType,
346 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module, final int line) {
347 if ((newBaseTypeBuilder == null && newBaseType == null) || (newBaseTypeBuilder != null && newBaseType != null)) {
348 throw new YangParseException(module.getName(), line,
349 "only one of newBaseTypeBuilder or newBaseType can be specified");
352 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
353 oldExtendedType.getQName());
354 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
355 TypeConstraints constraints;
356 if (newBaseType == null) {
357 tc.addFractionDigits(oldExtendedType.getFractionDigits());
358 tc.addLengths(oldExtendedType.getLengthConstraints());
359 tc.addPatterns(oldExtendedType.getPatternConstraints());
360 tc.addRanges(oldExtendedType.getRangeConstraints());
361 constraints = findConstraintsFromTypeBuilder(newBaseTypeBuilder, tc, modules, module, null);
362 newType.setTypedef(newBaseTypeBuilder);
364 constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
365 newType.setType(newBaseType);
368 newType.setPath(oldExtendedType.getPath());
369 newType.setDescription(oldExtendedType.getDescription());
370 newType.setReference(oldExtendedType.getReference());
371 newType.setStatus(oldExtendedType.getStatus());
372 newType.setLengths(constraints.getLength());
373 newType.setPatterns(constraints.getPatterns());
374 newType.setRanges(constraints.getRange());
375 newType.setFractionDigits(constraints.getFractionDigits());
376 newType.setUnits(oldExtendedType.getUnits());
377 newType.setDefaultValue(oldExtendedType.getDefaultValue());
378 newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
383 * Pull restrictions from type and add them to constraints.
385 * @param typeToResolve
386 * type from which constraints will be read
388 * constraints object to which constraints will be added
389 * @return constraints contstraints object containing constraints from given
392 private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
393 final TypeConstraints constraints) {
394 // union type cannot be restricted
395 if (typeToResolve instanceof UnionTypeDefinition) {
398 if (typeToResolve instanceof ExtendedType) {
399 ExtendedType extType = (ExtendedType) typeToResolve;
400 constraints.addFractionDigits(extType.getFractionDigits());
401 constraints.addLengths(extType.getLengthConstraints());
402 constraints.addPatterns(extType.getPatternConstraints());
403 constraints.addRanges(extType.getRangeConstraints());
404 return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
406 mergeConstraints(typeToResolve, constraints);
411 private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
412 final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
413 final ModuleBuilder builder, final SchemaContext context) {
415 // union and identityref types cannot be restricted
416 if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
420 if (nodeToResolve instanceof TypeDefinitionBuilder) {
421 TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
422 constraints.addFractionDigits(typedefToResolve.getFractionDigits());
423 constraints.addLengths(typedefToResolve.getLengths());
424 constraints.addPatterns(typedefToResolve.getPatterns());
425 constraints.addRanges(typedefToResolve.getRanges());
428 TypeDefinition<?> type = nodeToResolve.getType();
430 return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
432 QName qname = type.getQName();
433 if (type instanceof UnknownType) {
434 ModuleBuilder dependentModuleBuilder = ParserUtils.findModuleFromBuilders(modules, builder,
435 qname.getPrefix(), nodeToResolve.getLine());
436 if (dependentModuleBuilder == null) {
437 if (context == null) {
438 throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
439 "Failed to resolved type constraints.");
441 Module dm = ParserUtils.findModuleFromContext(context, builder, qname.getPrefix(),
442 nodeToResolve.getLine());
443 TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
444 return mergeConstraints(t, constraints);
447 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
448 qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
449 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
451 } else if (type instanceof ExtendedType) {
452 mergeConstraints(type, constraints);
454 TypeDefinition<?> base = ((ExtendedType) type).getBaseType();
455 if (base instanceof UnknownType) {
456 ModuleBuilder dependentModule = ParserUtils.findModuleFromBuilders(modules, builder, base
457 .getQName().getPrefix(), nodeToResolve.getLine());
458 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
459 .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
460 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
462 // it has to be base yang type
463 return mergeConstraints(type, constraints);
466 // it is base yang type
467 return mergeConstraints(type, constraints);
473 * Search for type definition builder by name.
475 * @param nodeToResolve
476 * node which contains unresolved type
477 * @param dependentModule
478 * module which should contains referenced type
480 * name of type definition
481 * @param currentModuleName
482 * name of current module
484 * current line in module
485 * @return typeDefinitionBuilder
487 private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
488 final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
489 Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
490 TypeDefinitionBuilder result = findTypedefBuilderByName(typedefs, typeName);
491 if (result != null) {
495 Builder parent = nodeToResolve.getParent();
496 while (parent != null) {
497 if (parent instanceof DataNodeContainerBuilder) {
498 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
499 } else if (parent instanceof RpcDefinitionBuilder) {
500 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
502 result = findTypedefBuilderByName(typedefs, typeName);
503 if (result == null) {
504 parent = parent.getParent();
510 if (result == null) {
511 throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");