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.controller.sal.binding.yang.types;
10 import org.opendaylight.controller.binding.generator.util.ReferencedTypeImpl;
11 import org.opendaylight.controller.binding.generator.util.Types;
12 import org.opendaylight.controller.binding.generator.util.generated.type.builder.EnumerationBuilderImpl;
13 import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
14 import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;
15 import org.opendaylight.controller.sal.binding.model.api.Enumeration;
16 import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
17 import org.opendaylight.controller.sal.binding.model.api.Type;
18 import org.opendaylight.controller.sal.binding.model.api.type.builder.EnumBuilder;
19 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
20 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTOBuilder;
21 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
22 import org.opendaylight.controller.yang.model.api.*;
23 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
24 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
25 import org.opendaylight.controller.yang.model.api.type.IdentityrefTypeDefinition;
26 import org.opendaylight.controller.yang.model.api.type.LeafrefTypeDefinition;
27 import org.opendaylight.controller.yang.model.api.type.UnionTypeDefinition;
28 import org.opendaylight.controller.yang.model.util.ExtendedType;
30 import java.util.HashMap;
31 import java.util.List;
35 import static org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil.*;
36 import static org.opendaylight.controller.yang.model.util.SchemaContextUtil.*;
38 public final class TypeProviderImpl implements TypeProvider {
40 private final SchemaContext schemaContext;
41 private Map<String, Map<String, Type>> genTypeDefsContextMap;
42 private final Map<SchemaPath, Type> referencedTypes;
44 public TypeProviderImpl(final SchemaContext schemaContext) {
45 if (schemaContext == null) {
46 throw new IllegalArgumentException("Schema Context cannot be null!");
49 this.schemaContext = schemaContext;
50 this.genTypeDefsContextMap = new HashMap<>();
51 this.referencedTypes = new HashMap<>();
52 resolveTypeDefsFromContext();
55 public void putReferencedType(final SchemaPath refTypePath,
57 if (refTypePath == null) {
58 throw new IllegalArgumentException("Path reference of " +
59 "Enumeration Type Definition cannot be NULL!");
62 if (refType == null) {
63 throw new IllegalArgumentException("Reference to Enumeration " +
64 "Type cannot be NULL!");
66 referencedTypes.put(refTypePath, refType);
72 * @see org.opendaylight.controller.yang.model.type.provider.TypeProvider#
73 * javaTypeForYangType(java.lang.String)
76 public Type javaTypeForYangType(String type) {
77 Type t = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
78 .javaTypeForYangType(type);
83 public Type javaTypeForSchemaDefinitionType(
84 final TypeDefinition<?> typeDefinition) {
85 Type returnType = null;
86 if (typeDefinition == null) {
87 throw new IllegalArgumentException("Type Definition cannot be " +
90 if (typeDefinition.getQName() == null) {
91 throw new IllegalArgumentException("Type Definition cannot have " +
92 "non specified QName (QName cannot be NULL!)");
94 if (typeDefinition.getQName().getLocalName() == null) {
95 throw new IllegalArgumentException("Type Definitions Local Name " +
98 final String typedefName = typeDefinition.getQName().getLocalName();
99 if (typeDefinition instanceof ExtendedType) {
100 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
102 if (baseTypeDef instanceof LeafrefTypeDefinition) {
103 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) baseTypeDef;
104 returnType = provideTypeForLeafref(leafref);
105 } else if (baseTypeDef instanceof IdentityrefTypeDefinition) {
107 } else if (baseTypeDef instanceof EnumTypeDefinition) {
108 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
109 returnType = resolveEnumFromTypeDefinition(enumTypeDef,
112 final Module module = findParentModuleForTypeDefinition(schemaContext,
114 if (module != null) {
115 final Map<String, Type> genTOs = genTypeDefsContextMap
116 .get(module.getName());
117 if (genTOs != null) {
118 returnType = genTOs.get(typedefName);
120 if (returnType == null) {
121 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
122 .javaTypeForSchemaDefinitionType(baseTypeDef);
127 if (typeDefinition instanceof LeafrefTypeDefinition) {
128 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
129 returnType = provideTypeForLeafref(leafref);
130 } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
133 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
134 .javaTypeForSchemaDefinitionType(typeDefinition);
137 //TODO: add throw exception when we will be able to resolve ALL yang
139 // if (returnType == null) {
140 // throw new IllegalArgumentException("Type Provider can't resolve " +
141 // "type for specified Type Definition " + typedefName);
146 public Type generatedTypeForExtendedDefinitionType(
147 final TypeDefinition<?> typeDefinition) {
148 Type returnType = null;
149 if (typeDefinition == null) {
150 throw new IllegalArgumentException("Type Definition cannot be " +
153 if (typeDefinition.getQName() == null) {
154 throw new IllegalArgumentException("Type Definition cannot have " +
155 "non specified QName (QName cannot be NULL!)");
157 if (typeDefinition.getQName() == null) {
158 throw new IllegalArgumentException("Type Definitions Local Name " +
162 final String typedefName = typeDefinition.getQName().getLocalName();
163 if (typeDefinition instanceof ExtendedType) {
164 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
166 if (!(baseTypeDef instanceof LeafrefTypeDefinition)
167 && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
168 final Module module = findParentModuleForTypeDefinition(schemaContext,
171 if (module != null) {
172 final Map<String, Type> genTOs = genTypeDefsContextMap
173 .get(module.getName());
174 if (genTOs != null) {
175 returnType = genTOs.get(typedefName);
183 private TypeDefinition<?> baseTypeDefForExtendedType(
184 final TypeDefinition<?> extendTypeDef) {
185 if (extendTypeDef == null) {
186 throw new IllegalArgumentException("Type Definiition reference " +
189 final TypeDefinition<?> baseTypeDef = extendTypeDef.getBaseType();
190 if (baseTypeDef instanceof ExtendedType) {
191 return baseTypeDefForExtendedType(baseTypeDef);
198 public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType) {
199 Type returnType = null;
200 if (leafrefType == null) {
201 throw new IllegalArgumentException("Leafref Type Definition " +
202 "reference cannot be NULL!");
205 if (leafrefType.getPathStatement() == null) {
206 throw new IllegalArgumentException("The Path Statement for " +
207 "Leafref Type Definition cannot be NULL!");
210 final RevisionAwareXPath xpath = leafrefType.getPathStatement();
211 final String strXPath = xpath.toString();
213 if (strXPath != null) {
214 if (strXPath.matches(".*//[.* | .*//].*")) {
215 returnType = Types.typeForClass(Object.class);
217 final Module module = findParentModuleForTypeDefinition(schemaContext, leafrefType);
218 if (module != null) {
219 final DataSchemaNode dataNode;
220 if (xpath.isAbsolute()) {
221 dataNode = findDataSchemaNode(schemaContext, module,
224 dataNode = findDataSchemaNodeForRelativeXPath(schemaContext,
225 module, leafrefType, xpath);
228 if (leafContainsEnumDefinition(dataNode)) {
229 returnType = referencedTypes.get(dataNode.getPath());
230 } else if (leafListContainsEnumDefinition(dataNode)) {
231 returnType = Types.listTypeFor(referencedTypes.get(
232 dataNode.getPath()));
234 returnType = resolveTypeFromDataSchemaNode(dataNode);
242 private boolean leafContainsEnumDefinition(final DataSchemaNode dataNode) {
243 if (dataNode instanceof LeafSchemaNode) {
244 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
245 if (leaf.getType() instanceof EnumTypeDefinition) {
252 private boolean leafListContainsEnumDefinition(
253 final DataSchemaNode dataNode) {
254 if (dataNode instanceof LeafListSchemaNode) {
255 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
256 if (leafList.getType() instanceof EnumTypeDefinition) {
263 private Enumeration resolveEnumFromTypeDefinition(
264 final EnumTypeDefinition enumTypeDef, final String enumName) {
265 if (enumTypeDef == null) {
266 throw new IllegalArgumentException("EnumTypeDefinition reference " +
269 if (enumTypeDef.getValues() == null) {
270 throw new IllegalArgumentException("EnumTypeDefinition MUST " +
271 "contain at least ONE value definition!");
273 if (enumTypeDef.getQName() == null) {
274 throw new IllegalArgumentException("EnumTypeDefinition MUST " +
275 "contain NON-NULL QName!");
277 if (enumTypeDef.getQName().getLocalName() == null) {
278 throw new IllegalArgumentException("Local Name in " +
279 "EnumTypeDefinition QName cannot be NULL!");
282 final String enumerationName = parseToClassName(enumName);
284 Module module = findParentModuleForTypeDefinition(schemaContext, enumTypeDef);
285 final String basePackageName = moduleNamespaceToPackageName(module);
287 final EnumBuilder enumBuilder = new EnumerationBuilderImpl(
288 basePackageName, enumerationName);
289 updateEnumPairsFromEnumTypeDef(enumTypeDef, enumBuilder);
290 return enumBuilder.toInstance(null);
293 private EnumBuilder resolveInnerEnumFromTypeDefinition(
294 final EnumTypeDefinition enumTypeDef, final String enumName,
295 final GeneratedTypeBuilder typeBuilder) {
296 if (enumTypeDef == null) {
297 throw new IllegalArgumentException("EnumTypeDefinition reference " +
300 if (enumTypeDef.getValues() == null) {
301 throw new IllegalArgumentException("EnumTypeDefinition MUST " +
302 "contain at least ONE value definition!");
304 if (enumTypeDef.getQName() == null) {
305 throw new IllegalArgumentException("EnumTypeDefinition MUST " +
306 "contain NON-NULL QName!");
308 if (enumTypeDef.getQName().getLocalName() == null) {
309 throw new IllegalArgumentException("Local Name in " +
310 "EnumTypeDefinition QName cannot be NULL!");
312 if (typeBuilder == null) {
313 throw new IllegalArgumentException("Generated Type Builder " +
314 "reference cannot be NULL!");
317 final String enumerationName = parseToClassName(enumName);
318 final EnumBuilder enumBuilder = typeBuilder
319 .addEnumeration(enumerationName);
321 updateEnumPairsFromEnumTypeDef(enumTypeDef, enumBuilder);
326 private void updateEnumPairsFromEnumTypeDef(
327 final EnumTypeDefinition enumTypeDef,
328 final EnumBuilder enumBuilder) {
329 if (enumBuilder != null) {
330 final List<EnumPair> enums = enumTypeDef.getValues();
333 for (final EnumPair enumPair : enums) {
334 if (enumPair != null) {
335 final String enumPairName = parseToClassName(enumPair
337 Integer enumPairValue = enumPair.getValue();
339 if (enumPairValue == null) {
340 enumPairValue = listIndex;
342 enumBuilder.addValue(enumPairName, enumPairValue);
350 private Type resolveTypeFromDataSchemaNode(final DataSchemaNode dataNode) {
351 Type returnType = null;
352 if (dataNode != null) {
353 if (dataNode instanceof LeafSchemaNode) {
354 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
355 returnType = javaTypeForSchemaDefinitionType(leaf.getType());
356 } else if (dataNode instanceof LeafListSchemaNode) {
357 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
358 returnType = javaTypeForSchemaDefinitionType(leafList.getType());
364 private void resolveTypeDefsFromContext() {
365 final Set<Module> modules = schemaContext.getModules();
366 if (modules == null) {
367 throw new IllegalArgumentException("Sef of Modules cannot be " +
370 for (final Module module : modules) {
371 if (module == null) {
374 final String moduleName = module.getName();
375 final String basePackageName = moduleNamespaceToPackageName(module);
377 final Set<TypeDefinition<?>> typeDefinitions = module
378 .getTypeDefinitions();
380 final Map<String, Type> typeMap = new HashMap<>();
381 genTypeDefsContextMap.put(moduleName, typeMap);
383 if ((typeDefinitions != null) && (basePackageName != null)) {
384 for (final TypeDefinition<?> typedef : typeDefinitions) {
385 typedefToGeneratedType(basePackageName, moduleName, typedef);
387 final List<ExtendedType> extUnions = UnionDependencySort
388 .sort(typeDefinitions);
389 for (final ExtendedType extUnionType : extUnions) {
390 addUnionGeneratedTypeDefinition(basePackageName, extUnionType);
396 private Type typedefToGeneratedType(final String basePackageName,
397 final String moduleName, final TypeDefinition<?> typedef) {
398 if ((basePackageName != null) && (moduleName != null)
399 && (typedef != null) && (typedef.getQName() != null)) {
402 final String typedefName = typedef.getQName().getLocalName();
403 final TypeDefinition<?> baseTypeDefinition = baseTypeDefForExtendedType(typedef);
404 if (!(baseTypeDefinition instanceof LeafrefTypeDefinition)
405 && !(baseTypeDefinition instanceof IdentityrefTypeDefinition)) {
407 if (baseTypeDefinition instanceof EnumTypeDefinition) {
408 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDefinition;
409 returnType = resolveEnumFromTypeDefinition(enumTypeDef,
413 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
414 .javaTypeForSchemaDefinitionType(baseTypeDefinition);
416 returnType = wrapJavaTypeIntoTO(basePackageName, typedef,
419 if (returnType != null) {
420 final Map<String, Type> typeMap = genTypeDefsContextMap.get
422 if (typeMap != null) {
423 typeMap.put(typedefName, returnType);
432 private GeneratedTransferObject wrapJavaTypeIntoTO(
433 final String basePackageName, final TypeDefinition<?> typedef,
434 final Type javaType) {
435 if (javaType != null) {
436 final String typedefName = typedef.getQName().getLocalName();
437 final String propertyName = parseToValidParamName(typedefName);
439 final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(
440 basePackageName, typedef);
442 final GeneratedPropertyBuilder genPropBuilder = genTOBuilder
443 .addProperty(propertyName);
445 genPropBuilder.addReturnType(javaType);
446 genTOBuilder.addEqualsIdentity(genPropBuilder);
447 genTOBuilder.addHashIdentity(genPropBuilder);
448 genTOBuilder.addToStringProperty(genPropBuilder);
449 return genTOBuilder.toInstance();
454 private void addUnionGeneratedTypeDefinition(final String basePackageName,
455 final TypeDefinition<?> typedef) {
456 if (basePackageName == null) {
457 throw new IllegalArgumentException("Base Package Name cannot be " +
460 if (typedef == null) {
461 throw new IllegalArgumentException("Type Definition cannot be " +
464 if (typedef.getQName() == null) {
465 throw new IllegalArgumentException("Type Definition cannot have " +
466 "non specified QName (QName cannot be NULL!)");
469 final TypeDefinition<?> baseTypeDefinition = typedef.getBaseType();
470 if ((baseTypeDefinition != null)
471 && (baseTypeDefinition instanceof UnionTypeDefinition)) {
472 final UnionTypeDefinition unionTypeDef = (UnionTypeDefinition) baseTypeDefinition;
473 final List<TypeDefinition<?>> unionTypes = unionTypeDef
475 final Module parentModule = findParentModuleForTypeDefinition(schemaContext,
478 Map<String, Type> genTOsMap = null;
479 if (parentModule != null && parentModule.getName() != null) {
480 genTOsMap = genTypeDefsContextMap.get(parentModule.getName());
483 final GeneratedTOBuilder unionGenTransObject = typedefToTransferObject(
484 basePackageName, typedef);
485 if ((unionTypes != null) && (unionGenTransObject != null)) {
486 for (final TypeDefinition<?> unionType : unionTypes) {
487 final String typeName = unionType.getQName()
489 if (unionType instanceof ExtendedType) {
490 final Module unionTypeModule = findParentModuleForTypeDefinition(schemaContext,
492 if (unionTypeModule != null && unionTypeModule.getName() != null) {
493 final Map<String, Type> innerGenTOs = genTypeDefsContextMap
494 .get(unionTypeModule.getName());
496 final GeneratedTransferObject genTransferObject =
497 (GeneratedTransferObject) innerGenTOs.get(typeName);
498 if (genTransferObject != null) {
499 updateUnionTypeAsProperty(unionGenTransObject,
501 genTransferObject.getName());
504 } else if (unionType instanceof EnumTypeDefinition) {
506 enumBuilder = resolveInnerEnumFromTypeDefinition(
507 (EnumTypeDefinition) unionType, typeName,
508 unionGenTransObject);
509 final Type enumRefType = new ReferencedTypeImpl(
510 enumBuilder.getPackageName(),
511 enumBuilder.getName());
512 updateUnionTypeAsProperty(unionGenTransObject,
513 enumRefType, typeName);
515 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
516 .javaTypeForSchemaDefinitionType(unionType);
517 if (javaType != null) {
518 updateUnionTypeAsProperty(unionGenTransObject,
523 genTOsMap.put(typedef.getQName().getLocalName(),
524 unionGenTransObject.toInstance());
529 private void updateUnionTypeAsProperty(
530 final GeneratedTOBuilder unionGenTransObject, final Type type,
531 final String propertyName) {
532 if (unionGenTransObject != null && type != null) {
533 final GeneratedPropertyBuilder propBuilder =
534 unionGenTransObject.addProperty(parseToValidParamName(
536 propBuilder.addReturnType(type);
537 propBuilder.setReadOnly(false);
539 if (!(type instanceof Enumeration)) {
540 unionGenTransObject.addEqualsIdentity(propBuilder);
541 unionGenTransObject.addHashIdentity(propBuilder);
542 unionGenTransObject.addToStringProperty(propBuilder);
547 private GeneratedTOBuilder typedefToTransferObject(
548 final String basePackageName, final TypeDefinition<?> typedef) {
550 final String packageName = packageNameForGeneratedType(basePackageName,
552 final String typeDefTOName = typedef.getQName().getLocalName();
554 if ((packageName != null) && (typedef != null)
555 && (typeDefTOName != null)) {
556 final String genTOName = parseToClassName(typeDefTOName);
557 final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(
558 packageName, genTOName);