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 " +
91 if (typeDefinition.getQName() == null) {
92 throw new IllegalArgumentException("Type Definition cannot have " +
93 "non specified QName (QName cannot be NULL!)");
96 if (typeDefinition.getQName().getLocalName() == null) {
97 throw new IllegalArgumentException("Type Definitions Local Name " +
100 final String typedefName = typeDefinition.getQName().getLocalName();
101 if (typeDefinition instanceof ExtendedType) {
102 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
104 if (baseTypeDef instanceof LeafrefTypeDefinition) {
105 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) baseTypeDef;
106 returnType = provideTypeForLeafref(leafref);
107 } else if (baseTypeDef instanceof IdentityrefTypeDefinition) {
109 } else if (baseTypeDef instanceof EnumTypeDefinition) {
110 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
111 returnType = resolveEnumFromTypeDefinition(enumTypeDef,
114 final Module module = findParentModuleForTypeDefinition(schemaContext,
116 if (module != null) {
117 final Map<String, Type> genTOs = genTypeDefsContextMap
118 .get(module.getName());
119 if (genTOs != null) {
120 returnType = genTOs.get(typedefName);
122 if (returnType == null) {
123 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
124 .javaTypeForSchemaDefinitionType(baseTypeDef);
129 if (typeDefinition instanceof LeafrefTypeDefinition) {
130 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
131 returnType = provideTypeForLeafref(leafref);
132 } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
135 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
136 .javaTypeForSchemaDefinitionType(typeDefinition);
142 public Type generatedTypeForExtendedDefinitionType(
143 final TypeDefinition<?> typeDefinition) {
144 Type returnType = null;
145 if (typeDefinition == null) {
146 throw new IllegalArgumentException("Type Definition cannot be " +
149 if (typeDefinition.getQName() == null) {
150 throw new IllegalArgumentException("Type Definition cannot have " +
151 "non specified QName (QName cannot be NULL!)");
153 if (typeDefinition.getQName() == null) {
154 throw new IllegalArgumentException("Type Definitions Local Name " +
158 final String typedefName = typeDefinition.getQName().getLocalName();
159 if (typeDefinition instanceof ExtendedType) {
160 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
162 if (!(baseTypeDef instanceof LeafrefTypeDefinition)
163 && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
164 final Module module = findParentModuleForTypeDefinition(schemaContext,
167 if (module != null) {
168 final Map<String, Type> genTOs = genTypeDefsContextMap
169 .get(module.getName());
170 if (genTOs != null) {
171 returnType = genTOs.get(typedefName);
179 private TypeDefinition<?> baseTypeDefForExtendedType(
180 final TypeDefinition<?> extendTypeDef) {
181 if (extendTypeDef == null) {
182 throw new IllegalArgumentException("Type Definiition reference " +
185 final TypeDefinition<?> baseTypeDef = extendTypeDef.getBaseType();
186 if (baseTypeDef instanceof ExtendedType) {
187 return baseTypeDefForExtendedType(baseTypeDef);
194 public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType) {
195 Type returnType = null;
196 if (leafrefType == null) {
197 throw new IllegalArgumentException("Leafref Type Definition " +
198 "reference cannot be NULL!");
201 if (leafrefType.getPathStatement() == null) {
202 throw new IllegalArgumentException("The Path Statement for " +
203 "Leafref Type Definition cannot be NULL!");
206 final RevisionAwareXPath xpath = leafrefType.getPathStatement();
207 final String strXPath = xpath.toString();
209 if (strXPath != null) {
210 if (strXPath.matches(".*//[.* | .*//].*")) {
211 returnType = Types.typeForClass(Object.class);
213 final Module module = findParentModuleForTypeDefinition(schemaContext, leafrefType);
214 if (module != null) {
215 final DataSchemaNode dataNode;
216 if (xpath.isAbsolute()) {
217 dataNode = findDataSchemaNode(schemaContext, module,
220 dataNode = findDataSchemaNodeForRelativeXPath(schemaContext,
221 module, leafrefType, xpath);
224 if (leafContainsEnumDefinition(dataNode)) {
225 returnType = referencedTypes.get(dataNode.getPath());
226 } else if (leafListContainsEnumDefinition(dataNode)) {
227 returnType = Types.listTypeFor(referencedTypes.get(
228 dataNode.getPath()));
230 returnType = resolveTypeFromDataSchemaNode(dataNode);
238 private boolean leafContainsEnumDefinition(final DataSchemaNode dataNode) {
239 if (dataNode instanceof LeafSchemaNode) {
240 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
241 if (leaf.getType() instanceof EnumTypeDefinition) {
248 private boolean leafListContainsEnumDefinition(
249 final DataSchemaNode dataNode) {
250 if (dataNode instanceof LeafListSchemaNode) {
251 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
252 if (leafList.getType() instanceof EnumTypeDefinition) {
259 private Enumeration resolveEnumFromTypeDefinition(
260 final EnumTypeDefinition enumTypeDef, final String enumName) {
261 if (enumTypeDef == null) {
262 throw new IllegalArgumentException("EnumTypeDefinition reference " +
265 if (enumTypeDef.getValues() == null) {
266 throw new IllegalArgumentException("EnumTypeDefinition MUST " +
267 "contain at least ONE value definition!");
269 if (enumTypeDef.getQName() == null) {
270 throw new IllegalArgumentException("EnumTypeDefinition MUST " +
271 "contain NON-NULL QName!");
273 if (enumTypeDef.getQName().getLocalName() == null) {
274 throw new IllegalArgumentException("Local Name in " +
275 "EnumTypeDefinition QName cannot be NULL!");
278 final String enumerationName = parseToClassName(enumName);
280 Module module = findParentModuleForTypeDefinition(schemaContext, enumTypeDef);
281 final String basePackageName = moduleNamespaceToPackageName(module);
283 final EnumBuilder enumBuilder = new EnumerationBuilderImpl(
284 basePackageName, enumerationName);
285 updateEnumPairsFromEnumTypeDef(enumTypeDef, enumBuilder);
286 return enumBuilder.toInstance(null);
289 private EnumBuilder resolveInnerEnumFromTypeDefinition(
290 final EnumTypeDefinition enumTypeDef, final String enumName,
291 final GeneratedTypeBuilder typeBuilder) {
292 if (enumTypeDef == null) {
293 throw new IllegalArgumentException("EnumTypeDefinition reference " +
296 if (enumTypeDef.getValues() == null) {
297 throw new IllegalArgumentException("EnumTypeDefinition MUST " +
298 "contain at least ONE value definition!");
300 if (enumTypeDef.getQName() == null) {
301 throw new IllegalArgumentException("EnumTypeDefinition MUST " +
302 "contain NON-NULL QName!");
304 if (enumTypeDef.getQName().getLocalName() == null) {
305 throw new IllegalArgumentException("Local Name in " +
306 "EnumTypeDefinition QName cannot be NULL!");
308 if (typeBuilder == null) {
309 throw new IllegalArgumentException("Generated Type Builder " +
310 "reference cannot be NULL!");
313 final String enumerationName = parseToClassName(enumName);
314 final EnumBuilder enumBuilder = typeBuilder
315 .addEnumeration(enumerationName);
317 updateEnumPairsFromEnumTypeDef(enumTypeDef, enumBuilder);
322 private void updateEnumPairsFromEnumTypeDef(
323 final EnumTypeDefinition enumTypeDef,
324 final EnumBuilder enumBuilder) {
325 if (enumBuilder != null) {
326 final List<EnumPair> enums = enumTypeDef.getValues();
329 for (final EnumPair enumPair : enums) {
330 if (enumPair != null) {
331 final String enumPairName = parseToClassName(enumPair
333 Integer enumPairValue = enumPair.getValue();
335 if (enumPairValue == null) {
336 enumPairValue = listIndex;
338 enumBuilder.addValue(enumPairName, enumPairValue);
346 private Type resolveTypeFromDataSchemaNode(final DataSchemaNode dataNode) {
347 Type returnType = null;
348 if (dataNode != null) {
349 if (dataNode instanceof LeafSchemaNode) {
350 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
351 returnType = javaTypeForSchemaDefinitionType(leaf.getType());
352 } else if (dataNode instanceof LeafListSchemaNode) {
353 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
354 returnType = javaTypeForSchemaDefinitionType(leafList.getType());
360 private void resolveTypeDefsFromContext() {
361 final Set<Module> modules = schemaContext.getModules();
362 if (modules == null) {
363 throw new IllegalArgumentException("Sef of Modules cannot be " +
366 for (final Module module : modules) {
367 if (module == null) {
370 final String moduleName = module.getName();
371 final String basePackageName = moduleNamespaceToPackageName(module);
373 final Set<TypeDefinition<?>> typeDefinitions = module
374 .getTypeDefinitions();
376 final Map<String, Type> typeMap = new HashMap<>();
377 genTypeDefsContextMap.put(moduleName, typeMap);
379 if ((typeDefinitions != null) && (basePackageName != null)) {
380 for (final TypeDefinition<?> typedef : typeDefinitions) {
381 typedefToGeneratedType(basePackageName, moduleName, typedef);
383 final List<ExtendedType> extUnions = UnionDependencySort
384 .sort(typeDefinitions);
385 for (final ExtendedType extUnionType : extUnions) {
386 addUnionGeneratedTypeDefinition(basePackageName, extUnionType);
392 private Type typedefToGeneratedType(final String basePackageName,
393 final String moduleName, final TypeDefinition<?> typedef) {
394 if ((basePackageName != null) && (moduleName != null)
395 && (typedef != null) && (typedef.getQName() != null)) {
398 final String typedefName = typedef.getQName().getLocalName();
399 final TypeDefinition<?> baseTypeDefinition = baseTypeDefForExtendedType(typedef);
400 if (!(baseTypeDefinition instanceof LeafrefTypeDefinition)
401 && !(baseTypeDefinition instanceof IdentityrefTypeDefinition)) {
403 if (baseTypeDefinition instanceof EnumTypeDefinition) {
404 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDefinition;
405 returnType = resolveEnumFromTypeDefinition(enumTypeDef,
409 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
410 .javaTypeForSchemaDefinitionType(baseTypeDefinition);
412 returnType = wrapJavaTypeIntoTO(basePackageName, typedef,
415 if (returnType != null) {
416 final Map<String, Type> typeMap = genTypeDefsContextMap.get
418 if (typeMap != null) {
419 typeMap.put(typedefName, returnType);
428 private GeneratedTransferObject wrapJavaTypeIntoTO(
429 final String basePackageName, final TypeDefinition<?> typedef,
430 final Type javaType) {
431 if (javaType != null) {
432 final String typedefName = typedef.getQName().getLocalName();
433 final String propertyName = parseToValidParamName(typedefName);
435 final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(
436 basePackageName, typedef);
438 final GeneratedPropertyBuilder genPropBuilder = genTOBuilder
439 .addProperty(propertyName);
441 genPropBuilder.addReturnType(javaType);
442 genTOBuilder.addEqualsIdentity(genPropBuilder);
443 genTOBuilder.addHashIdentity(genPropBuilder);
444 genTOBuilder.addToStringProperty(genPropBuilder);
445 return genTOBuilder.toInstance();
450 private void addUnionGeneratedTypeDefinition(final String basePackageName,
451 final TypeDefinition<?> typedef) {
452 if (basePackageName == null) {
453 throw new IllegalArgumentException("Base Package Name cannot be " +
456 if (typedef == null) {
457 throw new IllegalArgumentException("Type Definition cannot be " +
460 if (typedef.getQName() == null) {
461 throw new IllegalArgumentException("Type Definition cannot have " +
462 "non specified QName (QName cannot be NULL!)");
465 final TypeDefinition<?> baseTypeDefinition = typedef.getBaseType();
466 if ((baseTypeDefinition != null)
467 && (baseTypeDefinition instanceof UnionTypeDefinition)) {
468 final UnionTypeDefinition unionTypeDef = (UnionTypeDefinition) baseTypeDefinition;
469 final List<TypeDefinition<?>> unionTypes = unionTypeDef
471 final Module parentModule = findParentModuleForTypeDefinition(schemaContext,
474 Map<String, Type> genTOsMap = null;
475 if (parentModule != null && parentModule.getName() != null) {
476 genTOsMap = genTypeDefsContextMap.get(parentModule.getName());
479 final GeneratedTOBuilder unionGenTransObject = typedefToTransferObject(
480 basePackageName, typedef);
481 if ((unionTypes != null) && (unionGenTransObject != null)) {
482 for (final TypeDefinition<?> unionType : unionTypes) {
483 final String typeName = unionType.getQName()
485 if (unionType instanceof ExtendedType) {
486 final Module unionTypeModule = findParentModuleForTypeDefinition(schemaContext,
488 if (unionTypeModule != null && unionTypeModule.getName() != null) {
489 final Map<String, Type> innerGenTOs = genTypeDefsContextMap
490 .get(unionTypeModule.getName());
492 final GeneratedTransferObject genTransferObject =
493 (GeneratedTransferObject) innerGenTOs.get(typeName);
494 if (genTransferObject != null) {
495 updateUnionTypeAsProperty(unionGenTransObject,
497 genTransferObject.getName());
500 } else if (unionType instanceof EnumTypeDefinition) {
502 enumBuilder = resolveInnerEnumFromTypeDefinition(
503 (EnumTypeDefinition) unionType, typeName,
504 unionGenTransObject);
505 final Type enumRefType = new ReferencedTypeImpl(
506 enumBuilder.getPackageName(),
507 enumBuilder.getName());
508 updateUnionTypeAsProperty(unionGenTransObject,
509 enumRefType, typeName);
511 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
512 .javaTypeForSchemaDefinitionType(unionType);
513 if (javaType != null) {
514 updateUnionTypeAsProperty(unionGenTransObject,
519 genTOsMap.put(typedef.getQName().getLocalName(),
520 unionGenTransObject.toInstance());
525 private void updateUnionTypeAsProperty(
526 final GeneratedTOBuilder unionGenTransObject, final Type type,
527 final String propertyName) {
528 if (unionGenTransObject != null && type != null) {
529 final GeneratedPropertyBuilder propBuilder =
530 unionGenTransObject.addProperty(parseToValidParamName(
532 propBuilder.addReturnType(type);
533 propBuilder.setReadOnly(false);
535 if (!(type instanceof Enumeration)) {
536 unionGenTransObject.addEqualsIdentity(propBuilder);
537 unionGenTransObject.addHashIdentity(propBuilder);
538 unionGenTransObject.addToStringProperty(propBuilder);
543 private GeneratedTOBuilder typedefToTransferObject(
544 final String basePackageName, final TypeDefinition<?> typedef) {
546 final String packageName = packageNameForGeneratedType(basePackageName,
548 final String typeDefTOName = typedef.getQName().getLocalName();
550 if ((packageName != null) && (typedef != null)
551 && (typeDefTOName != null)) {
552 final String genTOName = parseToClassName(typeDefTOName);
553 final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(
554 packageName, genTOName);