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;
13 import java.util.ArrayList;
14 import java.util.Date;
15 import java.util.List;
18 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.api.type.UnsignedIntegerTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
30 import org.opendaylight.yangtools.yang.model.util.UnknownType;
31 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
32 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
33 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
34 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
35 import org.opendaylight.yangtools.yang.parser.util.TypeConstraints;
36 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
39 * Utility class which contains helper methods for dealing with type operations.
41 public final class TypeUtils {
47 * Resolve unknown type of node. It is assumed that type of node is either
48 * UnknownType or ExtendedType with UnknownType as base type.
50 * @param nodeToResolve
51 * node with type to resolve
57 public static void resolveType(final TypeAwareBuilder nodeToResolve,
58 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
59 final int line = nodeToResolve.getLine();
60 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
61 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
62 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
63 unknownTypeQName.getPrefix(), line);
65 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder, modules,
67 nodeToResolve.setTypedef(resolvedType);
71 * Resolve unknown type of node. It is assumed that type of node is either
72 * UnknownType or ExtendedType with UnknownType as base type.
74 * @param nodeToResolve
75 * node with type to resolve
81 * SchemaContext containing already resolved modules
83 public static void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
84 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
85 final SchemaContext context) {
86 final int line = nodeToResolve.getLine();
87 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
88 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
89 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
90 unknownTypeQName.getPrefix(), line);
92 if (dependentModuleBuilder == null) {
93 final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
94 final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
95 final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
97 if (nodeToResolveType instanceof ExtendedType) {
98 final ExtendedType extType = (ExtendedType) nodeToResolveType;
99 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module,
100 nodeToResolve.getLine());
102 nodeToResolve.setTypedef(newType);
104 if (nodeToResolve instanceof TypeDefinitionBuilder) {
105 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
106 TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
107 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
108 tdb.setLengths(tc.getLength());
109 tdb.setPatterns(tc.getPatterns());
110 tdb.setRanges(tc.getRange());
111 tdb.setFractionDigits(tc.getFractionDigits());
113 nodeToResolve.setType(type);
117 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder,
119 nodeToResolve.setTypedef(resolvedType);
123 public static void resolveTypeUnion(final UnionTypeBuilder union,
124 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
125 final List<TypeDefinition<?>> unionTypes = union.getTypes();
126 final List<TypeDefinition<?>> toRemove = new ArrayList<>();
127 for (TypeDefinition<?> unionType : unionTypes) {
128 if (unionType instanceof UnknownType) {
129 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, builder, unionType.getQName()
130 .getPrefix(), union.getLine());
131 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, unionType
132 .getQName().getLocalName(), builder.getName(), union.getLine());
133 union.setTypedef(resolvedType);
134 toRemove.add(unionType);
135 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
136 final UnknownType ut = (UnknownType) unionType.getBaseType();
137 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, builder, ut.getQName()
138 .getPrefix(), union.getLine());
139 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule, ut
140 .getQName().getLocalName(), builder.getName(), union.getLine());
141 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null,
142 (ExtendedType) unionType, modules, builder, union.getLine());
143 union.setTypedef(newType);
144 toRemove.add(unionType);
147 unionTypes.removeAll(toRemove);
151 * Resolve union type which contains one or more unresolved types.
154 * union type builder to resolve
160 * SchemaContext containing already resolved modules
162 public static void resolveTypeUnionWithContext(final UnionTypeBuilder union,
163 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
164 final SchemaContext context) {
165 final List<TypeDefinition<?>> unionTypes = union.getTypes();
166 final List<TypeDefinition<?>> toRemove = new ArrayList<>();
167 for (TypeDefinition<?> unionType : unionTypes) {
168 if (unionType instanceof UnknownType) {
169 resolveUnionUnknownType(union, (UnknownType) unionType, modules, module, context);
170 toRemove.add(unionType);
171 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
172 resolveUnionUnknownType(union, (ExtendedType) unionType, modules, module, context);
173 toRemove.add(unionType);
176 unionTypes.removeAll(toRemove);
179 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final UnknownType ut,
180 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
181 final SchemaContext context) {
182 final int line = union.getLine();
183 final QName utQName = ut.getQName();
184 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, utQName.getPrefix(), line);
186 if (dependentModuleBuilder == null) {
187 Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(), line);
188 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
189 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
192 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
193 utQName.getLocalName(), module.getName(), union.getLine());
194 union.setTypedef(resolvedType);
198 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final ExtendedType extType,
199 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
200 final SchemaContext context) {
201 final int line = union.getLine();
202 final TypeDefinition<?> extTypeBase = extType.getBaseType();
203 final UnknownType ut = (UnknownType) extTypeBase;
204 final QName utQName = ut.getQName();
205 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, utQName.getPrefix(), line);
207 if (dependentModuleBuilder == null) {
208 final Module dependentModule = findModuleFromContext(context, module, utQName.getPrefix(), line);
209 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
210 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
211 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(null, type, extType, modules, module, 0);
212 union.setTypedef(newType);
214 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModuleBuilder,
215 utQName.getLocalName(), module.getName(), line);
216 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules,
218 union.setTypedef(newType);
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 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
242 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
244 TypeDefinitionBuilder resolvedType;
245 if (nodeToResolveType instanceof ExtendedType) {
246 final ExtendedType extType = (ExtendedType) nodeToResolveType;
247 resolvedType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules, module,
248 nodeToResolve.getLine());
250 resolvedType = targetTypeBuilder;
253 // validate constraints
254 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
255 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
256 constraints.validateConstraints();
262 * Search types for type with given name.
268 * @return type with given name if present in collection, null otherwise
270 private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
271 for (TypeDefinitionBuilder td : types) {
272 if (td.getQName().getLocalName().equals(name)) {
283 * collection of types
286 * @return type with given name if it is present in collection, null
289 private static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
290 for (TypeDefinition<?> type : types) {
291 if (type.getQName().getLocalName().equals(typeName)) {
299 * Pull restriction from type and add them to constraints.
302 * type from which constraints will be read
304 * constraints object to which constraints will be added
306 private static TypeConstraints mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
307 if (type instanceof DecimalTypeDefinition) {
308 constraints.addRanges(((DecimalTypeDefinition) type).getRangeConstraints());
309 constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
310 } else if (type instanceof IntegerTypeDefinition) {
311 constraints.addRanges(((IntegerTypeDefinition) type).getRangeConstraints());
312 } else if (type instanceof UnsignedIntegerTypeDefinition) {
313 constraints.addRanges(((UnsignedIntegerTypeDefinition) type).getRangeConstraints());
314 } else if (type instanceof StringTypeDefinition) {
315 constraints.addPatterns(((StringTypeDefinition) type).getPatternConstraints());
316 constraints.addLengths(((StringTypeDefinition) type).getLengthConstraints());
317 } else if (type instanceof BinaryTypeDefinition) {
318 constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
319 } else if (type instanceof ExtendedType) {
320 constraints.addFractionDigits(((ExtendedType) type).getFractionDigits());
321 constraints.addLengths(((ExtendedType) type).getLengthConstraints());
322 constraints.addPatterns(((ExtendedType) type).getPatternConstraints());
323 constraints.addRanges(((ExtendedType) type).getRangeConstraints());
329 * Create new type builder based on old type with new base type. Note: only
330 * one of newBaseTypeBuilder or newBaseType can be specified.
332 * @param newBaseTypeBuilder
333 * new base type builder or null
335 * new base type or null
336 * @param oldExtendedType
343 * current line in module
344 * @return new type builder based on old type with new base type
346 private static TypeDefinitionBuilder extendedTypeWithNewBase(final TypeDefinitionBuilder newBaseTypeBuilder,
347 final TypeDefinition<?> newBaseType, final ExtendedType oldExtendedType,
348 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module, final int line) {
349 if ((newBaseTypeBuilder == null && newBaseType == null) || (newBaseTypeBuilder != null && newBaseType != null)) {
350 throw new YangParseException(module.getName(), line,
351 "only one of newBaseTypeBuilder or newBaseType can be specified");
354 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
355 oldExtendedType.getQName(), oldExtendedType.getPath());
356 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
357 TypeConstraints constraints;
358 if (newBaseType == null) {
359 tc.addFractionDigits(oldExtendedType.getFractionDigits());
360 tc.addLengths(oldExtendedType.getLengthConstraints());
361 tc.addPatterns(oldExtendedType.getPatternConstraints());
362 tc.addRanges(oldExtendedType.getRangeConstraints());
363 constraints = findConstraintsFromTypeBuilder(newBaseTypeBuilder, tc, modules, module, null);
364 newType.setTypedef(newBaseTypeBuilder);
366 constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
367 newType.setType(newBaseType);
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());
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 = BuilderUtils.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 = BuilderUtils.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 = BuilderUtils.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.");