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 java.util.ArrayList;
11 import java.util.Date;
12 import java.util.List;
15 import java.util.TreeMap;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
18 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
19 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
20 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
21 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
22 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
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.util.TypeConstraints;
31 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
34 * Utility class which contains helper methods for dealing with type operations.
36 public final class TypeUtils {
42 * Resolve unknown type of node. It is assumed that type of node is either
43 * UnknownType or ExtendedType with UnknownType as base type.
45 * @param nodeToResolve
46 * node with type to resolve
52 public static void resolveType(final TypeAwareBuilder nodeToResolve,
53 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
54 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
55 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
56 final ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(module, unknownTypeQName.getPrefix());
57 if (dependentModuleBuilder == null) {
58 throw new YangParseException(module.getName(), nodeToResolve.getLine(), "No module found for import "
59 + unknownTypeQName.getPrefix());
61 TypeDefinitionBuilder resolvedType = findUnknownTypeDefinition(nodeToResolve, dependentModuleBuilder, modules,
63 nodeToResolve.setTypedef(resolvedType);
67 * Resolve union type which contains one or more unresolved types.
70 * union type builder to resolve
76 public static void resolveTypeUnion(final UnionTypeBuilder union,
77 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
78 final List<TypeDefinition<?>> unionTypes = union.getTypes();
79 final List<TypeDefinition<?>> toRemove = new ArrayList<>();
80 for (TypeDefinition<?> unionType : unionTypes) {
81 if (unionType instanceof UnknownType) {
82 resolveUnionUnknownType(union, (UnknownType) unionType, modules, module);
83 toRemove.add(unionType);
84 } else if (unionType instanceof ExtendedType && unionType.getBaseType() instanceof UnknownType) {
85 resolveUnionUnknownType(union, (ExtendedType) unionType, modules, module);
86 toRemove.add(unionType);
89 unionTypes.removeAll(toRemove);
92 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final UnknownType ut,
93 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
94 final QName utQName = ut.getQName();
95 final ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(module, utQName.getPrefix());
96 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
97 utQName.getLocalName(), module.getName(), union.getLine());
98 union.setTypedef(resolvedType);
101 private static void resolveUnionUnknownType(final UnionTypeBuilder union, final ExtendedType extType,
102 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
103 final int line = union.getLine();
104 final TypeDefinition<?> extTypeBase = extType.getBaseType();
105 final UnknownType ut = (UnknownType) extTypeBase;
106 final QName utQName = ut.getQName();
107 final ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(module, utQName.getPrefix());
108 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModuleBuilder,
109 utQName.getLocalName(), module.getName(), line);
110 final TypeDefinitionBuilder newType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules,
112 union.setTypedef(newType);
116 * Find type definition of type of unresolved node.
118 * @param nodeToResolve
119 * node with unresolved type
120 * @param dependentModuleBuilder
121 * module in which type definition is present
126 * @return TypeDefinitionBuilder of node type
128 private static TypeDefinitionBuilder findUnknownTypeDefinition(final TypeAwareBuilder nodeToResolve,
129 final ModuleBuilder dependentModuleBuilder, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
130 final ModuleBuilder module) {
131 final int line = nodeToResolve.getLine();
132 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
133 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
134 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
135 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
137 TypeDefinitionBuilder resolvedType;
138 if (nodeToResolveType instanceof ExtendedType) {
139 final ExtendedType extType = (ExtendedType) nodeToResolveType;
140 resolvedType = extendedTypeWithNewBase(targetTypeBuilder, null, extType, modules, module,
141 nodeToResolve.getLine());
143 resolvedType = targetTypeBuilder;
146 // validate constraints
147 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
148 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module);
149 constraints.validateConstraints();
155 * Search types for type with given name.
161 * @return type with given name if present in collection, null otherwise
163 private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
164 for (TypeDefinitionBuilder td : types) {
165 if (td.getQName().getLocalName().equals(name)) {
173 * Pull restriction from type and add them to constraints.
176 * type from which constraints will be read
178 * constraints object to which constraints will be added
180 private static TypeConstraints mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
181 if (type instanceof DecimalTypeDefinition) {
182 constraints.addRanges(((DecimalTypeDefinition) type).getRangeConstraints());
183 constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
184 } else if (type instanceof IntegerTypeDefinition) {
185 constraints.addRanges(((IntegerTypeDefinition) type).getRangeConstraints());
186 } else if (type instanceof UnsignedIntegerTypeDefinition) {
187 constraints.addRanges(((UnsignedIntegerTypeDefinition) type).getRangeConstraints());
188 } else if (type instanceof StringTypeDefinition) {
189 constraints.addPatterns(((StringTypeDefinition) type).getPatternConstraints());
190 constraints.addLengths(((StringTypeDefinition) type).getLengthConstraints());
191 } else if (type instanceof BinaryTypeDefinition) {
192 constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
193 } else if (type instanceof ExtendedType) {
194 constraints.addFractionDigits(((ExtendedType) type).getFractionDigits());
195 constraints.addLengths(((ExtendedType) type).getLengthConstraints());
196 constraints.addPatterns(((ExtendedType) type).getPatternConstraints());
197 constraints.addRanges(((ExtendedType) type).getRangeConstraints());
203 * Create new type builder based on old type with new base type. Note: only
204 * one of newBaseTypeBuilder or newBaseType can be specified.
206 * @param newBaseTypeBuilder
207 * new base type builder or null
209 * new base type or null
210 * @param oldExtendedType
217 * current line in module
218 * @return new type builder based on old type with new base type
220 private static TypeDefinitionBuilder extendedTypeWithNewBase(final TypeDefinitionBuilder newBaseTypeBuilder,
221 final TypeDefinition<?> newBaseType, final ExtendedType oldExtendedType,
222 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module, final int line) {
223 if ((newBaseTypeBuilder == null && newBaseType == null) || (newBaseTypeBuilder != null && newBaseType != null)) {
224 throw new YangParseException(module.getName(), line,
225 "only one of newBaseTypeBuilder or newBaseType can be specified");
228 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
229 oldExtendedType.getQName(), oldExtendedType.getPath());
230 final TypeConstraints tc = new TypeConstraints(module.getName(), line);
231 TypeConstraints constraints;
232 if (newBaseType == null) {
233 tc.addFractionDigits(oldExtendedType.getFractionDigits());
234 tc.addLengths(oldExtendedType.getLengthConstraints());
235 tc.addPatterns(oldExtendedType.getPatternConstraints());
236 tc.addRanges(oldExtendedType.getRangeConstraints());
237 constraints = findConstraintsFromTypeBuilder(newBaseTypeBuilder, tc, modules, module);
238 newType.setTypedef(newBaseTypeBuilder);
240 constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
241 newType.setType(newBaseType);
244 newType.setDescription(oldExtendedType.getDescription());
245 newType.setReference(oldExtendedType.getReference());
246 newType.setStatus(oldExtendedType.getStatus());
247 newType.setLengths(constraints.getLength());
248 newType.setPatterns(constraints.getPatterns());
249 newType.setRanges(constraints.getRange());
250 newType.setFractionDigits(constraints.getFractionDigits());
251 newType.setUnits(oldExtendedType.getUnits());
252 newType.setDefaultValue(oldExtendedType.getDefaultValue());
257 * Pull restrictions from type and add them to constraints.
259 * @param typeToResolve
260 * type from which constraints will be read
262 * constraints object to which constraints will be added
263 * @return constraints contstraints object containing constraints from given
266 private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
267 final TypeConstraints constraints) {
268 // union type cannot be restricted
269 if (typeToResolve instanceof UnionTypeDefinition) {
272 if (typeToResolve instanceof ExtendedType) {
273 ExtendedType extType = (ExtendedType) typeToResolve;
274 constraints.addFractionDigits(extType.getFractionDigits());
275 constraints.addLengths(extType.getLengthConstraints());
276 constraints.addPatterns(extType.getPatternConstraints());
277 constraints.addRanges(extType.getRangeConstraints());
278 return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
280 mergeConstraints(typeToResolve, constraints);
285 private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
286 final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
287 final ModuleBuilder builder) {
289 // union and identityref types cannot be restricted
290 if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
294 if (nodeToResolve instanceof TypeDefinitionBuilder) {
295 TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
296 constraints.addFractionDigits(typedefToResolve.getFractionDigits());
297 constraints.addLengths(typedefToResolve.getLengths());
298 constraints.addPatterns(typedefToResolve.getPatterns());
299 constraints.addRanges(typedefToResolve.getRanges());
302 TypeDefinition<?> type = nodeToResolve.getType();
304 return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder);
306 QName qname = type.getQName();
307 if (type instanceof UnknownType) {
308 ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(builder, qname.getPrefix());
309 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
310 qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
311 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder);
312 } else if (type instanceof ExtendedType) {
313 mergeConstraints(type, constraints);
315 TypeDefinition<?> base = ((ExtendedType) type).getBaseType();
316 if (base instanceof UnknownType) {
317 ModuleBuilder dependentModule = BuilderUtils.getModuleByPrefix(builder, base.getQName().getPrefix());
318 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
319 .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
320 return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule);
322 // it has to be base yang type
323 return mergeConstraints(type, constraints);
326 // it is base yang type
327 return mergeConstraints(type, constraints);
333 * Search for type definition builder by name.
335 * @param nodeToResolve
336 * node which contains unresolved type
337 * @param dependentModule
338 * module which should contains referenced type
340 * name of type definition
341 * @param currentModuleName
342 * name of current module
344 * current line in module
345 * @return typeDefinitionBuilder
347 private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
348 final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
349 Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
350 TypeDefinitionBuilder result = findTypedefBuilderByName(typedefs, typeName);
351 if (result != null) {
355 Builder parent = nodeToResolve.getParent();
356 while (parent != null) {
357 if (parent instanceof DataNodeContainerBuilder) {
358 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
359 } else if (parent instanceof RpcDefinitionBuilder) {
360 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
362 result = findTypedefBuilderByName(typedefs, typeName);
363 if (result == null) {
364 parent = parent.getParent();
370 if (result == null) {
371 throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");