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 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 dependentModule = findDependentModuleBuilder(modules, module, unknownTypeQName.getPrefix(),
68 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve, dependentModule,
69 unknownTypeQName.getLocalName(), module.getName(), line);
71 if (nodeToResolveType instanceof ExtendedType) {
72 final ExtendedType extType = (ExtendedType) nodeToResolveType;
73 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
74 modules, module, nodeToResolve.getLine());
75 resolvedType = newType;
77 resolvedType = targetTypeBuilder;
80 // validate constraints
81 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
82 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
83 constraints.validateConstraints();
85 nodeToResolve.setTypedef(resolvedType);
89 * Resolve unknown type of node. It is assumed that type of node is either
90 * UnknownType or ExtendedType with UnknownType as base type.
92 * @param nodeToResolve
93 * node with type to resolve
99 * SchemaContext containing already resolved modules
101 public static void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
102 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
103 final SchemaContext context) {
104 TypeDefinitionBuilder resolvedType = null;
105 final int line = nodeToResolve.getLine();
106 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
107 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
108 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
109 unknownTypeQName.getPrefix(), line);
111 if (dependentModuleBuilder == null) {
112 final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
113 final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
114 final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
116 if (nodeToResolveType instanceof ExtendedType) {
117 final ExtendedType extType = (ExtendedType) nodeToResolveType;
118 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, module,
119 nodeToResolve.getLine());
121 nodeToResolve.setTypedef(newType);
123 if (nodeToResolve instanceof TypeDefinitionBuilder) {
124 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
125 TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
126 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
127 tdb.setLengths(tc.getLength());
128 tdb.setPatterns(tc.getPatterns());
129 tdb.setRanges(tc.getRange());
130 tdb.setFractionDigits(tc.getFractionDigits());
132 nodeToResolve.setType(type);
136 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
137 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
139 if (nodeToResolveType instanceof ExtendedType) {
140 final ExtendedType extType = (ExtendedType) nodeToResolveType;
141 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
142 modules, module, nodeToResolve.getLine());
143 resolvedType = newType;
145 resolvedType = targetTypeBuilder;
148 // validate constraints
149 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints(
150 module.getName(), nodeToResolve.getLine()), modules, module, context);
151 constraints.validateConstraints();
153 nodeToResolve.setTypedef(resolvedType);
157 public static void resolveTypeUnion(final UnionTypeBuilder union,
158 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
160 final List<TypeDefinition<?>> unionTypes = union.getTypes();
161 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
162 for (TypeDefinition<?> unionType : unionTypes) {
163 if (unionType instanceof UnknownType) {
164 final UnknownType ut = (UnknownType) unionType;
165 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
166 .getPrefix(), union.getLine());
167 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, ut
168 .getQName().getLocalName(), builder.getName(), union.getLine());
169 union.setTypedef(resolvedType);
171 } else if (unionType instanceof ExtendedType) {
172 final ExtendedType extType = (ExtendedType) unionType;
173 final TypeDefinition<?> extTypeBase = extType.getBaseType();
174 if (extTypeBase instanceof UnknownType) {
175 final UnknownType ut = (UnknownType) extTypeBase;
176 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
177 .getPrefix(), union.getLine());
178 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule,
179 ut.getQName().getLocalName(), builder.getName(), union.getLine());
181 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
182 extType, modules, builder, union.getLine());
184 union.setTypedef(newType);
185 toRemove.add(extType);
189 unionTypes.removeAll(toRemove);
192 public static void resolveTypeUnionWithContext(final UnionTypeBuilder union,
193 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder,
194 final SchemaContext context) {
196 final List<TypeDefinition<?>> unionTypes = union.getTypes();
197 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
198 for (TypeDefinition<?> unionType : unionTypes) {
199 if (unionType instanceof UnknownType) {
200 final UnknownType ut = (UnknownType) unionType;
201 final QName utQName = ut.getQName();
202 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
203 utQName.getPrefix(), union.getLine());
205 if (dependentModuleBuilder == null) {
206 Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
208 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
209 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
213 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
214 utQName.getLocalName(), builder.getName(), union.getLine());
215 union.setTypedef(resolvedType);
219 } else if (unionType instanceof ExtendedType) {
220 final ExtendedType extType = (ExtendedType) unionType;
221 TypeDefinition<?> extTypeBase = extType.getBaseType();
222 if (extTypeBase instanceof UnknownType) {
223 final UnknownType ut = (UnknownType) extTypeBase;
224 final QName utQName = ut.getQName();
225 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
226 utQName.getPrefix(), union.getLine());
228 if (dependentModuleBuilder == null) {
229 final Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
231 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
232 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
233 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, builder, 0);
235 union.setTypedef(newType);
236 toRemove.add(extType);
238 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union,
239 dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine());
241 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
242 extType, modules, builder, union.getLine());
244 union.setTypedef(newType);
245 toRemove.add(extType);
250 unionTypes.removeAll(toRemove);
254 * Search types for type with given name.
260 * @return type with given name if present in collection, null otherwise
262 private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
263 for (TypeDefinitionBuilder td : types) {
264 if (td.getQName().getLocalName().equals(name)) {
275 * collection of types
278 * @return type with given name if it is present in collection, null
281 private static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
282 for (TypeDefinition<?> type : types) {
283 if (type.getQName().getLocalName().equals(typeName)) {
291 * Pull restriction from type and add them to constraints.
296 private static void mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
297 if (type instanceof DecimalTypeDefinition) {
298 constraints.addRanges(((DecimalTypeDefinition) type).getRangeStatements());
299 constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
300 } else if (type instanceof IntegerTypeDefinition) {
301 constraints.addRanges(((IntegerTypeDefinition) type).getRangeStatements());
302 } else if (type instanceof StringTypeDefinition) {
303 constraints.addPatterns(((StringTypeDefinition) type).getPatterns());
304 constraints.addLengths(((StringTypeDefinition) type).getLengthStatements());
305 } else if (type instanceof BinaryTypeDefinition) {
306 constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
311 * Create new type builder based on old type with new base type.
314 * new base type builder
315 * @param oldExtendedType
322 * current line in module
323 * @return new type builder based on old type with new base type
325 private static TypeDefinitionBuilder extendedTypeWithNewBaseTypeBuilder(final TypeDefinitionBuilder newBaseType,
326 final ExtendedType oldExtendedType, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
327 final ModuleBuilder module, final int line) {
328 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
329 tc.addFractionDigits(oldExtendedType.getFractionDigits());
330 tc.addLengths(oldExtendedType.getLengths());
331 tc.addPatterns(oldExtendedType.getPatterns());
332 tc.addRanges(oldExtendedType.getRanges());
334 final TypeConstraints constraints = findConstraintsFromTypeBuilder(newBaseType, tc, modules, module, null);
335 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
336 oldExtendedType.getQName());
337 newType.setTypedef(newBaseType);
338 newType.setPath(oldExtendedType.getPath());
339 newType.setDescription(oldExtendedType.getDescription());
340 newType.setReference(oldExtendedType.getReference());
341 newType.setStatus(oldExtendedType.getStatus());
342 newType.setLengths(constraints.getLength());
343 newType.setPatterns(constraints.getPatterns());
344 newType.setRanges(constraints.getRange());
345 newType.setFractionDigits(constraints.getFractionDigits());
346 newType.setUnits(oldExtendedType.getUnits());
347 newType.setDefaultValue(oldExtendedType.getDefaultValue());
348 newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
353 * Create new type builder based on old type with new base type.
357 * @param oldExtendedType
364 * current line in module
365 * @return new type builder based on old type with new base type
367 private static TypeDefinitionBuilder extendedTypeWithNewBaseType(final TypeDefinition<?> newBaseType,
368 final ExtendedType oldExtendedType, final ModuleBuilder module, final int line) {
369 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
371 final TypeConstraints constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
372 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
373 oldExtendedType.getQName());
374 newType.setType(newBaseType);
375 newType.setPath(oldExtendedType.getPath());
376 newType.setDescription(oldExtendedType.getDescription());
377 newType.setReference(oldExtendedType.getReference());
378 newType.setStatus(oldExtendedType.getStatus());
379 newType.setLengths(constraints.getLength());
380 newType.setPatterns(constraints.getPatterns());
381 newType.setRanges(constraints.getRange());
382 newType.setFractionDigits(constraints.getFractionDigits());
383 newType.setUnits(oldExtendedType.getUnits());
384 newType.setDefaultValue(oldExtendedType.getDefaultValue());
385 newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
390 * Pull restrictions from type and add them to constraints.
392 * @param typeToResolve
393 * type from which constraints will be read
395 * constraints object to which constraints will be added
396 * @return constraints contstraints object containing constraints from given
399 private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
400 final TypeConstraints constraints) {
401 // union type cannot be restricted
402 if (typeToResolve instanceof UnionTypeDefinition) {
405 if (typeToResolve instanceof ExtendedType) {
406 ExtendedType extType = (ExtendedType) typeToResolve;
407 constraints.addFractionDigits(extType.getFractionDigits());
408 constraints.addLengths(extType.getLengths());
409 constraints.addPatterns(extType.getPatterns());
410 constraints.addRanges(extType.getRanges());
411 return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
413 mergeConstraints(typeToResolve, constraints);
418 private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
419 final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
420 final ModuleBuilder builder, final SchemaContext context) {
422 // union and identityref types cannot be restricted
423 if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
427 if (nodeToResolve instanceof TypeDefinitionBuilder) {
428 TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
429 constraints.addFractionDigits(typedefToResolve.getFractionDigits());
430 constraints.addLengths(typedefToResolve.getLengths());
431 constraints.addPatterns(typedefToResolve.getPatterns());
432 constraints.addRanges(typedefToResolve.getRanges());
435 TypeDefinition<?> type = nodeToResolve.getType();
437 return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
439 QName qname = type.getQName();
440 if (type instanceof UnknownType) {
441 ModuleBuilder dependentModuleBuilder = ParserUtils.findDependentModuleBuilder(modules, builder,
442 qname.getPrefix(), nodeToResolve.getLine());
443 if (dependentModuleBuilder == null) {
444 if (context == null) {
445 throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
446 "Failed to resolved type constraints.");
448 Module dm = ParserUtils.findModuleFromContext(context, builder, qname.getPrefix(),
449 nodeToResolve.getLine());
450 TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
451 if (t instanceof ExtendedType) {
452 ExtendedType extType = (ExtendedType) t;
453 constraints.addFractionDigits(extType.getFractionDigits());
454 constraints.addLengths(extType.getLengths());
455 constraints.addPatterns(extType.getPatterns());
456 constraints.addRanges(extType.getRanges());
459 mergeConstraints(t, constraints);
463 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
464 qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
465 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
467 } else if (type instanceof ExtendedType) {
468 ExtendedType extType = (ExtendedType) type;
469 constraints.addFractionDigits(extType.getFractionDigits());
470 constraints.addLengths(extType.getLengths());
471 constraints.addPatterns(extType.getPatterns());
472 constraints.addRanges(extType.getRanges());
474 TypeDefinition<?> base = extType.getBaseType();
475 if (base instanceof UnknownType) {
476 ModuleBuilder dependentModule = ParserUtils.findDependentModuleBuilder(modules, builder, base
477 .getQName().getPrefix(), nodeToResolve.getLine());
478 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
479 .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
480 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
482 // it has to be base yang type
483 mergeConstraints(type, constraints);
487 // it is base yang type
488 mergeConstraints(type, constraints);
495 * Search for type definition builder by name.
497 * @param dirtyNodeSchemaPath
498 * schema path of node which contains unresolved type
499 * @param dependentModule
500 * module which should contains referenced type
502 * name of type definition
503 * @param currentModuleName
504 * name of current module
506 * current line in module
509 private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
510 final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
512 TypeDefinitionBuilder result = null;
514 Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
515 result = findTypedefBuilderByName(typedefs, typeName);
516 if (result != null) {
520 Builder parent = nodeToResolve.getParent();
521 while (parent != null) {
522 if (parent instanceof DataNodeContainerBuilder) {
523 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
524 } else if (parent instanceof RpcDefinitionBuilder) {
525 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
527 result = findTypedefBuilderByName(typedefs, typeName);
528 if (result == null) {
529 parent = parent.getParent();
535 if (result == null) {
536 throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");