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.BinaryTypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
28 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
29 import org.opendaylight.yangtools.yang.model.util.UnknownType;
30 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
31 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
32 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
33 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
34 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
35 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
36 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
37 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
38 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
41 * Utility class which contains helper methods for dealing with type operations.
43 public final class TypeUtils {
49 * Resolve unknown type of node. It is assumed that type of node is either
50 * UnknownType or ExtendedType with UnknownType as base type.
52 * @param nodeToResolve
53 * node with type to resolve
59 public static void resolveType(final TypeAwareBuilder nodeToResolve,
60 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
61 TypeDefinitionBuilder resolvedType = null;
62 final int line = nodeToResolve.getLine();
63 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
64 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
65 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
66 unknownTypeQName.getPrefix(), line);
68 resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder, modules, module);
69 nodeToResolve.setTypedef(resolvedType);
73 * Resolve unknown type of node. It is assumed that type of node is either
74 * UnknownType or ExtendedType with UnknownType as base type.
76 * @param nodeToResolve
77 * node with type to resolve
83 * SchemaContext containing already resolved modules
85 public static void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
86 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
87 final SchemaContext context) {
88 TypeDefinitionBuilder resolvedType = null;
89 final int line = nodeToResolve.getLine();
90 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
91 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
92 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
93 unknownTypeQName.getPrefix(), line);
95 if (dependentModuleBuilder == null) {
96 final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
97 final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
98 final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
100 if (nodeToResolveType instanceof ExtendedType) {
101 final ExtendedType extType = (ExtendedType) nodeToResolveType;
102 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module,
103 nodeToResolve.getLine());
105 nodeToResolve.setTypedef(newType);
107 if (nodeToResolve instanceof TypeDefinitionBuilder) {
108 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
109 TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
110 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
111 tdb.setLengths(tc.getLength());
112 tdb.setPatterns(tc.getPatterns());
113 tdb.setRanges(tc.getRange());
114 tdb.setFractionDigits(tc.getFractionDigits());
116 nodeToResolve.setType(type);
120 resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder, modules, module);
121 nodeToResolve.setTypedef(resolvedType);
125 public static void resolveTypeUnion(final UnionTypeBuilder union,
126 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
128 final List<TypeDefinition<?>> unionTypes = union.getTypes();
129 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
130 for (TypeDefinition<?> unionType : unionTypes) {
131 if (unionType instanceof UnknownType) {
132 final UnknownType ut = (UnknownType) unionType;
133 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
134 .getPrefix(), union.getLine());
135 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, ut
136 .getQName().getLocalName(), builder.getName(), union.getLine());
137 union.setTypedef(resolvedType);
139 } else if (unionType instanceof ExtendedType) {
140 final ExtendedType extType = (ExtendedType) unionType;
141 final TypeDefinition<?> extTypeBase = extType.getBaseType();
142 if (extTypeBase instanceof UnknownType) {
143 final UnknownType ut = (UnknownType) extTypeBase;
144 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
145 .getPrefix(), union.getLine());
146 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule,
147 ut.getQName().getLocalName(), builder.getName(), union.getLine());
149 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null, extType,
150 modules, builder, union.getLine());
152 union.setTypedef(newType);
153 toRemove.add(extType);
157 unionTypes.removeAll(toRemove);
160 public static void resolveTypeUnionWithContext(final UnionTypeBuilder union,
161 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
162 final SchemaContext context) {
164 final List<TypeDefinition<?>> unionTypes = union.getTypes();
165 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
166 for (TypeDefinition<?> unionType : unionTypes) {
167 if (unionType instanceof UnknownType) {
168 final UnknownType ut = (UnknownType) unionType;
169 final QName utQName = ut.getQName();
170 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
171 utQName.getPrefix(), union.getLine());
173 if (dependentModuleBuilder == null) {
174 Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(),
176 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
177 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
181 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
182 utQName.getLocalName(), module.getName(), union.getLine());
183 union.setTypedef(resolvedType);
187 } else if (unionType instanceof ExtendedType) {
188 final ExtendedType extType = (ExtendedType) unionType;
189 TypeDefinition<?> extTypeBase = extType.getBaseType();
190 if (extTypeBase instanceof UnknownType) {
191 final UnknownType ut = (UnknownType) extTypeBase;
192 final QName utQName = ut.getQName();
193 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
194 utQName.getPrefix(), union.getLine());
196 if (dependentModuleBuilder == null) {
197 final Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(),
199 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
200 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
201 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules,
204 union.setTypedef(newType);
205 toRemove.add(extType);
207 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union,
208 dependentModuleBuilder, utQName.getLocalName(), module.getName(), union.getLine());
210 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null, extType,
211 modules, module, union.getLine());
213 union.setTypedef(newType);
214 toRemove.add(extType);
219 unionTypes.removeAll(toRemove);
223 * Find type definition of type of unresolved node.
225 * @param nodeToResolve
226 * node with unresolved type
227 * @param dependentModuleBuilder
228 * module in which type definition is present
233 * @return TypeDefinitionBuilder of node type
235 private static TypeDefinitionBuilder findUnknownTypeDefinition(final TypeAwareBuilder nodeToResolve,
236 final ModuleBuilder dependentModuleBuilder, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
237 final ModuleBuilder module) {
238 final int line = nodeToResolve.getLine();
239 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
240 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
241 TypeDefinitionBuilder resolvedType = null;
242 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
243 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
245 if (nodeToResolveType instanceof ExtendedType) {
246 final ExtendedType extType = (ExtendedType) nodeToResolveType;
247 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules,
248 module, nodeToResolve.getLine());
249 resolvedType = newType;
251 resolvedType = targetTypeBuilder;
254 // validate constraints
255 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
256 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
257 constraints.validateConstraints();
263 * Search types for type with given name.
269 * @return type with given name if present in collection, null otherwise
271 private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
272 for (TypeDefinitionBuilder td : types) {
273 if (td.getQName().getLocalName().equals(name)) {
284 * collection of types
287 * @return type with given name if it is present in collection, null
290 private static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
291 for (TypeDefinition<?> type : types) {
292 if (type.getQName().getLocalName().equals(typeName)) {
300 * Pull restriction from type and add them to constraints.
303 * type from which constraints will be read
305 * constraints object to which constraints will be added
307 private static TypeConstraints mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
308 if (type instanceof DecimalTypeDefinition) {
309 constraints.addRanges(((DecimalTypeDefinition) type).getRangeConstraints());
310 constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
311 } else if (type instanceof IntegerTypeDefinition) {
312 constraints.addRanges(((IntegerTypeDefinition) type).getRangeConstraints());
313 } else if (type instanceof StringTypeDefinition) {
314 constraints.addPatterns(((StringTypeDefinition) type).getPatternConstraints());
315 constraints.addLengths(((StringTypeDefinition) type).getLengthConstraints());
316 } else if (type instanceof BinaryTypeDefinition) {
317 constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
318 } else if (type instanceof ExtendedType) {
319 constraints.addFractionDigits(((ExtendedType) type).getFractionDigits());
320 constraints.addLengths(((ExtendedType) type).getLengthConstraints());
321 constraints.addPatterns(((ExtendedType) type).getPatternConstraints());
322 constraints.addRanges(((ExtendedType) type).getRangeConstraints());
328 * Create new type builder based on old type with new base type. Note: only
329 * one of newBaseTypeBuilder or newBaseType can be specified.
331 * @param newBaseTypeBuilder
332 * new base type builder or null
334 * new base type or null
335 * @param oldExtendedType
342 * current line in module
343 * @return new type builder based on old type with new base type
345 private static TypeDefinitionBuilder extendedTypeWithNewBase(final TypeDefinitionBuilder newBaseTypeBuilder,
346 final TypeDefinition<?> newBaseType, final ExtendedType oldExtendedType,
347 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module, final int line) {
348 if ((newBaseTypeBuilder == null && newBaseType == null) || (newBaseTypeBuilder != null && newBaseType != null)) {
349 throw new YangParseException(module.getName(), line,
350 "only one of newBaseTypeBuilder or newBaseType can be specified");
353 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
354 oldExtendedType.getQName());
355 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
356 TypeConstraints constraints = null;
357 if (newBaseType == null) {
358 tc.addFractionDigits(oldExtendedType.getFractionDigits());
359 tc.addLengths(oldExtendedType.getLengthConstraints());
360 tc.addPatterns(oldExtendedType.getPatternConstraints());
361 tc.addRanges(oldExtendedType.getRangeConstraints());
362 constraints = findConstraintsFromTypeBuilder(newBaseTypeBuilder, tc, modules, module, null);
363 newType.setTypedef(newBaseTypeBuilder);
365 constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
366 newType.setType(newBaseType);
369 newType.setPath(oldExtendedType.getPath());
370 newType.setDescription(oldExtendedType.getDescription());
371 newType.setReference(oldExtendedType.getReference());
372 newType.setStatus(oldExtendedType.getStatus());
373 newType.setLengths(constraints.getLength());
374 newType.setPatterns(constraints.getPatterns());
375 newType.setRanges(constraints.getRange());
376 newType.setFractionDigits(constraints.getFractionDigits());
377 newType.setUnits(oldExtendedType.getUnits());
378 newType.setDefaultValue(oldExtendedType.getDefaultValue());
379 newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
384 * Pull restrictions from type and add them to constraints.
386 * @param typeToResolve
387 * type from which constraints will be read
389 * constraints object to which constraints will be added
390 * @return constraints contstraints object containing constraints from given
393 private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
394 final TypeConstraints constraints) {
395 // union type cannot be restricted
396 if (typeToResolve instanceof UnionTypeDefinition) {
399 if (typeToResolve instanceof ExtendedType) {
400 ExtendedType extType = (ExtendedType) typeToResolve;
401 constraints.addFractionDigits(extType.getFractionDigits());
402 constraints.addLengths(extType.getLengthConstraints());
403 constraints.addPatterns(extType.getPatternConstraints());
404 constraints.addRanges(extType.getRangeConstraints());
405 return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
407 mergeConstraints(typeToResolve, constraints);
412 private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
413 final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
414 final ModuleBuilder builder, final SchemaContext context) {
416 // union and identityref types cannot be restricted
417 if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
421 if (nodeToResolve instanceof TypeDefinitionBuilder) {
422 TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
423 constraints.addFractionDigits(typedefToResolve.getFractionDigits());
424 constraints.addLengths(typedefToResolve.getLengths());
425 constraints.addPatterns(typedefToResolve.getPatterns());
426 constraints.addRanges(typedefToResolve.getRanges());
429 TypeDefinition<?> type = nodeToResolve.getType();
431 return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
433 QName qname = type.getQName();
434 if (type instanceof UnknownType) {
435 ModuleBuilder dependentModuleBuilder = ParserUtils.findDependentModuleBuilder(modules, builder,
436 qname.getPrefix(), nodeToResolve.getLine());
437 if (dependentModuleBuilder == null) {
438 if (context == null) {
439 throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
440 "Failed to resolved type constraints.");
442 Module dm = ParserUtils.findModuleFromContext(context, builder, qname.getPrefix(),
443 nodeToResolve.getLine());
444 TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
445 return mergeConstraints(t, constraints);
448 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
449 qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
450 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
452 } else if (type instanceof ExtendedType) {
453 mergeConstraints(type, constraints);
455 TypeDefinition<?> base = ((ExtendedType) type).getBaseType();
456 if (base instanceof UnknownType) {
457 ModuleBuilder dependentModule = ParserUtils.findDependentModuleBuilder(modules, builder, base
458 .getQName().getPrefix(), nodeToResolve.getLine());
459 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
460 .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
461 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
463 // it has to be base yang type
464 return mergeConstraints(type, constraints);
467 // it is base yang type
468 return mergeConstraints(type, constraints);
474 * Search for type definition builder by name.
476 * @param dirtyNodeSchemaPath
477 * schema path of node which contains unresolved type
478 * @param dependentModule
479 * module which should contains referenced type
481 * name of type definition
482 * @param currentModuleName
483 * name of current module
485 * current line in module
488 private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
489 final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
491 TypeDefinitionBuilder result = null;
493 Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
494 result = findTypedefBuilderByName(typedefs, typeName);
495 if (result != null) {
499 Builder parent = nodeToResolve.getParent();
500 while (parent != null) {
501 if (parent instanceof DataNodeContainerBuilder) {
502 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
503 } else if (parent instanceof RpcDefinitionBuilder) {
504 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
506 result = findTypedefBuilderByName(typedefs, typeName);
507 if (result == null) {
508 parent = parent.getParent();
514 if (result == null) {
515 throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");