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.SchemaPath;
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.Int16;
32 import org.opendaylight.yangtools.yang.model.util.Int32;
33 import org.opendaylight.yangtools.yang.model.util.Int64;
34 import org.opendaylight.yangtools.yang.model.util.Int8;
35 import org.opendaylight.yangtools.yang.model.util.Uint16;
36 import org.opendaylight.yangtools.yang.model.util.Uint32;
37 import org.opendaylight.yangtools.yang.model.util.Uint64;
38 import org.opendaylight.yangtools.yang.model.util.Uint8;
39 import org.opendaylight.yangtools.yang.model.util.UnknownType;
40 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
41 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
42 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
43 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
44 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
45 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
46 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
47 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
48 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
51 * Utility class which contains helper methods for dealing with type operations.
53 public class TypeUtils {
59 * Resolve unknown type of node. It is assumed that type of node is either
60 * UnknownType or ExtendedType with UnknownType as base type.
62 * @param nodeToResolve
63 * node with type to resolve
69 public static void resolveType(final TypeAwareBuilder nodeToResolve,
70 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
71 TypeDefinitionBuilder resolvedType = null;
72 final int line = nodeToResolve.getLine();
73 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
74 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
75 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, unknownTypeQName.getPrefix(),
78 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve, dependentModule,
79 unknownTypeQName.getLocalName(), module.getName(), line);
81 if (nodeToResolveType instanceof ExtendedType) {
82 final ExtendedType extType = (ExtendedType) nodeToResolveType;
83 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
84 modules, module, nodeToResolve.getLine());
85 resolvedType = newType;
87 resolvedType = targetTypeBuilder;
90 // validate constraints
91 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
92 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
93 constraints.validateConstraints();
95 nodeToResolve.setTypedef(resolvedType);
99 * Resolve unknown type of node. It is assumed that type of node is either
100 * UnknownType or ExtendedType with UnknownType as base type.
102 * @param nodeToResolve
103 * node with type to resolve
109 * SchemaContext containing already resolved modules
111 public static void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
112 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
113 final SchemaContext context) {
114 TypeDefinitionBuilder resolvedType = null;
115 final int line = nodeToResolve.getLine();
116 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
117 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
118 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
119 unknownTypeQName.getPrefix(), line);
121 if (dependentModuleBuilder == null) {
122 final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
123 final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
124 final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
126 if (nodeToResolveType instanceof ExtendedType) {
127 final ExtendedType extType = (ExtendedType) nodeToResolveType;
128 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, module,
129 nodeToResolve.getLine());
131 nodeToResolve.setTypedef(newType);
133 if (nodeToResolve instanceof TypeDefinitionBuilder) {
134 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
135 TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
136 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
137 tdb.setLengths(tc.getLength());
138 tdb.setPatterns(tc.getPatterns());
139 tdb.setRanges(tc.getRange());
140 tdb.setFractionDigits(tc.getFractionDigits());
142 nodeToResolve.setType(type);
146 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
147 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
149 if (nodeToResolveType instanceof ExtendedType) {
150 final ExtendedType extType = (ExtendedType) nodeToResolveType;
151 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
152 modules, module, nodeToResolve.getLine());
153 resolvedType = newType;
155 resolvedType = targetTypeBuilder;
158 // validate constraints
159 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints(
160 module.getName(), nodeToResolve.getLine()), modules, module, context);
161 constraints.validateConstraints();
163 nodeToResolve.setTypedef(resolvedType);
167 public static void resolveTypeUnion(final UnionTypeBuilder union,
168 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
170 final List<TypeDefinition<?>> unionTypes = union.getTypes();
171 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
172 for (TypeDefinition<?> unionType : unionTypes) {
173 if (unionType instanceof UnknownType) {
174 final UnknownType ut = (UnknownType) unionType;
175 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
176 .getPrefix(), union.getLine());
177 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, ut
178 .getQName().getLocalName(), builder.getName(), union.getLine());
179 union.setTypedef(resolvedType);
181 } else if (unionType instanceof ExtendedType) {
182 final ExtendedType extType = (ExtendedType) unionType;
183 final TypeDefinition<?> extTypeBase = extType.getBaseType();
184 if (extTypeBase instanceof UnknownType) {
185 final UnknownType ut = (UnknownType) extTypeBase;
186 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
187 .getPrefix(), union.getLine());
188 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule,
189 ut.getQName().getLocalName(), builder.getName(), union.getLine());
191 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
192 extType, modules, builder, union.getLine());
194 union.setTypedef(newType);
195 toRemove.add(extType);
199 unionTypes.removeAll(toRemove);
202 public static void resolveTypeUnionWithContext(final UnionTypeBuilder union,
203 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder,
204 final SchemaContext context) {
206 final List<TypeDefinition<?>> unionTypes = union.getTypes();
207 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
208 for (TypeDefinition<?> unionType : unionTypes) {
209 if (unionType instanceof UnknownType) {
210 final UnknownType ut = (UnknownType) unionType;
211 final QName utQName = ut.getQName();
212 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
213 utQName.getPrefix(), union.getLine());
215 if (dependentModuleBuilder == null) {
216 Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
218 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
219 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
223 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
224 utQName.getLocalName(), builder.getName(), union.getLine());
225 union.setTypedef(resolvedType);
229 } else if (unionType instanceof ExtendedType) {
230 final ExtendedType extType = (ExtendedType) unionType;
231 TypeDefinition<?> extTypeBase = extType.getBaseType();
232 if (extTypeBase instanceof UnknownType) {
233 final UnknownType ut = (UnknownType) extTypeBase;
234 final QName utQName = ut.getQName();
235 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
236 utQName.getPrefix(), union.getLine());
238 if (dependentModuleBuilder == null) {
239 final Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
241 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
242 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
243 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, builder, 0);
245 union.setTypedef(newType);
246 toRemove.add(extType);
248 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union,
249 dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine());
251 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
252 extType, modules, builder, union.getLine());
254 union.setTypedef(newType);
255 toRemove.add(extType);
260 unionTypes.removeAll(toRemove);
264 * Search types for type with given name.
270 * @return type with given name if present in collection, null otherwise
272 private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
273 for (TypeDefinitionBuilder td : types) {
274 if (td.getQName().getLocalName().equals(name)) {
285 * collection of types
288 * @return type with given name if it is present in collection, null
291 private static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
292 for (TypeDefinition<?> type : types) {
293 if (type.getQName().getLocalName().equals(typeName)) {
301 * Pull restriction from type and add them to constraints.
306 private static void mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
307 if (type instanceof DecimalTypeDefinition) {
308 constraints.addRanges(((DecimalTypeDefinition) type).getRangeStatements());
309 constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
310 } else if (type instanceof IntegerTypeDefinition) {
311 constraints.addRanges(((IntegerTypeDefinition) type).getRangeStatements());
312 } else if (type instanceof StringTypeDefinition) {
313 constraints.addPatterns(((StringTypeDefinition) type).getPatterns());
314 constraints.addLengths(((StringTypeDefinition) type).getLengthStatements());
315 } else if (type instanceof BinaryTypeDefinition) {
316 constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
321 * Create new ExtendedType based on given type and with schema path.
324 * schema path for new type
329 static ExtendedType createNewExtendedType(final ExtendedType oldType, final SchemaPath newPath) {
330 QName qname = oldType.getQName();
331 TypeDefinition<?> newBaseType = ParserUtils.createCorrectTypeDefinition(newPath, oldType.getBaseType());
332 String desc = oldType.getDescription();
333 String ref = oldType.getReference();
334 ExtendedType.Builder builder = new ExtendedType.Builder(qname, newBaseType, desc, ref, newPath);
335 builder.status(oldType.getStatus());
336 builder.lengths(oldType.getLengths());
337 builder.patterns(oldType.getPatterns());
338 builder.ranges(oldType.getRanges());
339 builder.fractionDigits(oldType.getFractionDigits());
340 builder.unknownSchemaNodes(oldType.getUnknownSchemaNodes());
341 return builder.build();
344 static IntegerTypeDefinition createNewIntType(final SchemaPath newSchemaPath,
345 final IntegerTypeDefinition type) {
346 final String localName = type.getQName().getLocalName();
347 if ("int8".equals(localName)) {
348 return new Int8(newSchemaPath);
349 } else if ("int16".equals(localName)) {
350 return new Int16(newSchemaPath);
351 } else if ("int32".equals(localName)) {
352 return new Int32(newSchemaPath);
353 } else if ("int64".equals(localName)) {
354 return new Int64(newSchemaPath);
360 static UnsignedIntegerTypeDefinition createNewUintType(final SchemaPath newSchemaPath,
361 final UnsignedIntegerTypeDefinition type) {
362 final String localName = type.getQName().getLocalName();
363 if ("uint8".equals(localName)) {
364 return new Uint8(newSchemaPath);
365 } else if ("uint16".equals(localName)) {
366 return new Uint16(newSchemaPath);
367 } else if ("uint32".equals(localName)) {
368 return new Uint32(newSchemaPath);
369 } else if ("uint64".equals(localName)) {
370 return new Uint64(newSchemaPath);
377 * Create new type builder based on old type with new base type.
380 * new base type builder
381 * @param oldExtendedType
388 * current line in module
389 * @return new type builder based on old type with new base type
391 private static TypeDefinitionBuilder extendedTypeWithNewBaseTypeBuilder(final TypeDefinitionBuilder newBaseType,
392 final ExtendedType oldExtendedType, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
393 final ModuleBuilder module, final int line) {
394 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
395 tc.addFractionDigits(oldExtendedType.getFractionDigits());
396 tc.addLengths(oldExtendedType.getLengths());
397 tc.addPatterns(oldExtendedType.getPatterns());
398 tc.addRanges(oldExtendedType.getRanges());
400 final TypeConstraints constraints = findConstraintsFromTypeBuilder(newBaseType, tc, modules, module, null);
401 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
402 oldExtendedType.getQName());
403 newType.setTypedef(newBaseType);
404 newType.setPath(oldExtendedType.getPath());
405 newType.setDescription(oldExtendedType.getDescription());
406 newType.setReference(oldExtendedType.getReference());
407 newType.setStatus(oldExtendedType.getStatus());
408 newType.setLengths(constraints.getLength());
409 newType.setPatterns(constraints.getPatterns());
410 newType.setRanges(constraints.getRange());
411 newType.setFractionDigits(constraints.getFractionDigits());
412 newType.setUnits(oldExtendedType.getUnits());
413 newType.setDefaultValue(oldExtendedType.getDefaultValue());
414 newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
419 * Create new type builder based on old type with new base type.
423 * @param oldExtendedType
430 * current line in module
431 * @return new type builder based on old type with new base type
433 private static TypeDefinitionBuilder extendedTypeWithNewBaseType(final TypeDefinition<?> newBaseType,
434 final ExtendedType oldExtendedType, final ModuleBuilder module, final int line) {
435 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
437 final TypeConstraints constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
438 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
439 oldExtendedType.getQName());
440 newType.setType(newBaseType);
441 newType.setPath(oldExtendedType.getPath());
442 newType.setDescription(oldExtendedType.getDescription());
443 newType.setReference(oldExtendedType.getReference());
444 newType.setStatus(oldExtendedType.getStatus());
445 newType.setLengths(constraints.getLength());
446 newType.setPatterns(constraints.getPatterns());
447 newType.setRanges(constraints.getRange());
448 newType.setFractionDigits(constraints.getFractionDigits());
449 newType.setUnits(oldExtendedType.getUnits());
450 newType.setDefaultValue(oldExtendedType.getDefaultValue());
451 newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
456 * Pull restrictions from type and add them to constraints.
458 * @param typeToResolve
459 * type from which constraints will be read
461 * constraints object to which constraints will be added
462 * @return constraints contstraints object containing constraints from given
465 private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
466 final TypeConstraints constraints) {
467 // union type cannot be restricted
468 if (typeToResolve instanceof UnionTypeDefinition) {
471 if (typeToResolve instanceof ExtendedType) {
472 ExtendedType extType = (ExtendedType) typeToResolve;
473 constraints.addFractionDigits(extType.getFractionDigits());
474 constraints.addLengths(extType.getLengths());
475 constraints.addPatterns(extType.getPatterns());
476 constraints.addRanges(extType.getRanges());
477 return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
479 mergeConstraints(typeToResolve, constraints);
484 private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
485 final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
486 final ModuleBuilder builder, final SchemaContext context) {
488 // union and identityref types cannot be restricted
489 if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
493 if (nodeToResolve instanceof TypeDefinitionBuilder) {
494 TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
495 constraints.addFractionDigits(typedefToResolve.getFractionDigits());
496 constraints.addLengths(typedefToResolve.getLengths());
497 constraints.addPatterns(typedefToResolve.getPatterns());
498 constraints.addRanges(typedefToResolve.getRanges());
501 TypeDefinition<?> type = nodeToResolve.getType();
503 return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
505 QName qname = type.getQName();
506 if (type instanceof UnknownType) {
507 ModuleBuilder dependentModuleBuilder = ParserUtils.findDependentModuleBuilder(modules, builder,
508 qname.getPrefix(), nodeToResolve.getLine());
509 if (dependentModuleBuilder == null) {
510 if (context == null) {
511 throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
512 "Failed to resolved type constraints.");
514 Module dm = ParserUtils.findModuleFromContext(context, builder, qname.getPrefix(),
515 nodeToResolve.getLine());
516 TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
517 if (t instanceof ExtendedType) {
518 ExtendedType extType = (ExtendedType) t;
519 constraints.addFractionDigits(extType.getFractionDigits());
520 constraints.addLengths(extType.getLengths());
521 constraints.addPatterns(extType.getPatterns());
522 constraints.addRanges(extType.getRanges());
525 mergeConstraints(t, constraints);
529 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
530 qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
531 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
533 } else if (type instanceof ExtendedType) {
534 ExtendedType extType = (ExtendedType) type;
535 constraints.addFractionDigits(extType.getFractionDigits());
536 constraints.addLengths(extType.getLengths());
537 constraints.addPatterns(extType.getPatterns());
538 constraints.addRanges(extType.getRanges());
540 TypeDefinition<?> base = extType.getBaseType();
541 if (base instanceof UnknownType) {
542 ModuleBuilder dependentModule = ParserUtils.findDependentModuleBuilder(modules, builder, base
543 .getQName().getPrefix(), nodeToResolve.getLine());
544 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
545 .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
546 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
548 // it has to be base yang type
549 mergeConstraints(type, constraints);
553 // it is base yang type
554 mergeConstraints(type, constraints);
561 * Search for type definition builder by name.
563 * @param dirtyNodeSchemaPath
564 * schema path of node which contains unresolved type
565 * @param dependentModule
566 * module which should contains referenced type
568 * name of type definition
569 * @param currentModuleName
570 * name of current module
572 * current line in module
575 private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
576 final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
578 TypeDefinitionBuilder result = null;
580 Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
581 result = findTypedefBuilderByName(typedefs, typeName);
582 if (result != null) {
586 Builder parent = nodeToResolve.getParent();
587 while (parent != null) {
588 if (parent instanceof DataNodeContainerBuilder) {
589 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
590 } else if (parent instanceof RpcDefinitionBuilder) {
591 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
593 result = findTypedefBuilderByName(typedefs, typeName);
594 if (result == null) {
595 parent = parent.getParent();
601 if (result == null) {
602 throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");