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.common.QName;
23 import org.opendaylight.controller.yang.model.api.*;
24 import org.opendaylight.controller.yang.model.api.type.*;
25 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
26 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
27 import org.opendaylight.controller.yang.model.util.ExtendedType;
29 import java.util.HashMap;
30 import java.util.List;
34 import static org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil.*;
35 import static org.opendaylight.controller.yang.model.util.SchemaContextUtil.*;
37 public final class TypeProviderImpl implements TypeProvider {
39 private final SchemaContext schemaContext;
40 private Map<String, Map<String, Type>> genTypeDefsContextMap;
41 private final Map<SchemaPath, Type> referencedTypes;
43 public TypeProviderImpl(final SchemaContext schemaContext) {
44 if (schemaContext == null) {
45 throw new IllegalArgumentException("Schema Context cannot be null!");
48 this.schemaContext = schemaContext;
49 this.genTypeDefsContextMap = new HashMap<>();
50 this.referencedTypes = new HashMap<>();
51 resolveTypeDefsFromContext();
54 public void putReferencedType(final SchemaPath refTypePath,
56 if (refTypePath == null) {
57 throw new IllegalArgumentException("Path reference of "
58 + "Enumeration Type Definition cannot be NULL!");
61 if (refType == null) {
62 throw new IllegalArgumentException("Reference to Enumeration "
63 + "Type cannot be NULL!");
65 referencedTypes.put(refTypePath, refType);
71 * @see org.opendaylight.controller.yang.model.type.provider.TypeProvider#
72 * javaTypeForYangType(java.lang.String)
75 public Type javaTypeForYangType(String type) {
76 Type t = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
77 .javaTypeForYangType(type);
82 public Type javaTypeForSchemaDefinitionType(
83 final TypeDefinition<?> typeDefinition) {
84 Type returnType = null;
85 if (typeDefinition == null) {
86 throw new IllegalArgumentException("Type Definition cannot be NULL!");
88 if (typeDefinition.getQName() == null) {
89 throw new IllegalArgumentException("Type Definition cannot have non specified QName (QName cannot be NULL!)");
91 if (typeDefinition.getQName().getLocalName() == null) {
92 throw new IllegalArgumentException("Type Definitions Local Name cannot be NULL!");
94 final String typedefName = typeDefinition.getQName().getLocalName();
95 if (typeDefinition instanceof ExtendedType) {
96 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
98 if (baseTypeDef instanceof LeafrefTypeDefinition) {
99 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) baseTypeDef;
100 returnType = provideTypeForLeafref(leafref);
101 } else if (baseTypeDef instanceof IdentityrefTypeDefinition) {
102 final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) baseTypeDef;
103 returnType = returnTypeForIdentityref(idref);
104 } else if (baseTypeDef instanceof EnumTypeDefinition) {
105 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
106 returnType = resolveEnumFromTypeDefinition(enumTypeDef,
109 final Module module = findParentModuleForTypeDefinition(
110 schemaContext, typeDefinition);
111 if (module != null) {
112 final Map<String, Type> genTOs = genTypeDefsContextMap
113 .get(module.getName());
114 if (genTOs != null) {
115 returnType = genTOs.get(typedefName);
117 if (returnType == null) {
118 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
119 .javaTypeForSchemaDefinitionType(baseTypeDef);
124 if (typeDefinition instanceof LeafrefTypeDefinition) {
125 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
126 returnType = provideTypeForLeafref(leafref);
127 } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
128 final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) typeDefinition;
129 returnType = returnTypeForIdentityref(idref);
131 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
132 .javaTypeForSchemaDefinitionType(typeDefinition);
135 // TODO: add throw exception when we will be able to resolve ALL yang
137 // if (returnType == null) {
138 // throw new IllegalArgumentException("Type Provider can't resolve " +
139 // "type for specified Type Definition " + typedefName);
144 private Type returnTypeForIdentityref(IdentityrefTypeDefinition idref) {
145 QName baseIdQName = idref.getIdentity();
146 Module module = schemaContext.findModuleByNamespace(baseIdQName.getNamespace());
147 IdentitySchemaNode identity = null;
148 for (IdentitySchemaNode id : module.getIdentities()) {
149 if (id.getQName().equals(baseIdQName)) {
153 if (identity == null) {
154 throw new IllegalArgumentException("Target identity '" + baseIdQName + "' do not exists");
157 final String basePackageName = moduleNamespaceToPackageName(module);
158 final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
159 final String genTypeName = parseToClassName(identity.getQName().getLocalName());
161 Type baseType = Types.typeForClass(Class.class);
162 Type paramType = Types.wildcardTypeFor(packageName, genTypeName);
163 Type returnType = Types.parameterizedTypeFor(baseType, paramType);
167 public Type generatedTypeForExtendedDefinitionType(
168 final TypeDefinition<?> typeDefinition) {
169 Type returnType = null;
170 if (typeDefinition == null) {
171 throw new IllegalArgumentException("Type Definition cannot be NULL!");
173 if (typeDefinition.getQName() == null) {
174 throw new IllegalArgumentException("Type Definition cannot have non specified QName (QName cannot be NULL!)");
176 if (typeDefinition.getQName() == null) {
177 throw new IllegalArgumentException("Type Definitions Local Name cannot be NULL!");
180 final String typedefName = typeDefinition.getQName().getLocalName();
181 if (typeDefinition instanceof ExtendedType) {
182 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
184 if (!(baseTypeDef instanceof LeafrefTypeDefinition)
185 && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
186 final Module module = findParentModuleForTypeDefinition(
187 schemaContext, typeDefinition);
189 if (module != null) {
190 final Map<String, Type> genTOs = genTypeDefsContextMap
191 .get(module.getName());
192 if (genTOs != null) {
193 returnType = genTOs.get(typedefName);
201 private TypeDefinition<?> baseTypeDefForExtendedType(
202 final TypeDefinition<?> extendTypeDef) {
203 if (extendTypeDef == null) {
204 throw new IllegalArgumentException("Type Definiition reference cannot be NULL!");
206 final TypeDefinition<?> baseTypeDef = extendTypeDef.getBaseType();
207 if (baseTypeDef instanceof ExtendedType) {
208 return baseTypeDefForExtendedType(baseTypeDef);
215 public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType) {
216 Type returnType = null;
217 if (leafrefType == null) {
218 throw new IllegalArgumentException("Leafref Type Definition reference cannot be NULL!");
221 if (leafrefType.getPathStatement() == null) {
222 throw new IllegalArgumentException("The Path Statement for Leafref Type Definition cannot be NULL!");
225 final RevisionAwareXPath xpath = leafrefType.getPathStatement();
226 final String strXPath = xpath.toString();
228 if (strXPath != null) {
229 if (strXPath.matches(".*//[.* | .*//].*")) {
230 returnType = Types.typeForClass(Object.class);
232 final Module module = findParentModuleForTypeDefinition(
233 schemaContext, leafrefType);
234 if (module != null) {
235 final DataSchemaNode dataNode;
236 if (xpath.isAbsolute()) {
237 dataNode = findDataSchemaNode(schemaContext, module,
240 dataNode = findDataSchemaNodeForRelativeXPath(
241 schemaContext, module, leafrefType, xpath);
244 if (leafContainsEnumDefinition(dataNode)) {
245 returnType = referencedTypes.get(dataNode.getPath());
246 } else if (leafListContainsEnumDefinition(dataNode)) {
247 returnType = Types.listTypeFor(referencedTypes
248 .get(dataNode.getPath()));
250 returnType = resolveTypeFromDataSchemaNode(dataNode);
258 private boolean leafContainsEnumDefinition(final DataSchemaNode dataNode) {
259 if (dataNode instanceof LeafSchemaNode) {
260 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
261 if (leaf.getType() instanceof EnumTypeDefinition) {
268 private boolean leafListContainsEnumDefinition(final DataSchemaNode dataNode) {
269 if (dataNode instanceof LeafListSchemaNode) {
270 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
271 if (leafList.getType() instanceof EnumTypeDefinition) {
278 private Enumeration resolveEnumFromTypeDefinition(
279 final EnumTypeDefinition enumTypeDef, final String enumName) {
280 if (enumTypeDef == null) {
281 throw new IllegalArgumentException("EnumTypeDefinition reference cannot be NULL!");
283 if (enumTypeDef.getValues() == null) {
284 throw new IllegalArgumentException("EnumTypeDefinition MUST contain at least ONE value definition!");
286 if (enumTypeDef.getQName() == null) {
287 throw new IllegalArgumentException("EnumTypeDefinition MUST contain NON-NULL QName!");
289 if (enumTypeDef.getQName().getLocalName() == null) {
290 throw new IllegalArgumentException("Local Name in EnumTypeDefinition QName cannot be NULL!");
293 final String enumerationName = parseToClassName(enumName);
295 Module module = findParentModuleForTypeDefinition(schemaContext,
297 final String basePackageName = moduleNamespaceToPackageName(module);
299 final EnumBuilder enumBuilder = new EnumerationBuilderImpl(
300 basePackageName, enumerationName);
301 updateEnumPairsFromEnumTypeDef(enumTypeDef, enumBuilder);
302 return enumBuilder.toInstance(null);
305 private EnumBuilder resolveInnerEnumFromTypeDefinition(
306 final EnumTypeDefinition enumTypeDef, final String enumName,
307 final GeneratedTypeBuilder typeBuilder) {
308 if (enumTypeDef == null) {
309 throw new IllegalArgumentException("EnumTypeDefinition reference cannot be NULL!");
311 if (enumTypeDef.getValues() == null) {
312 throw new IllegalArgumentException("EnumTypeDefinition MUST contain at least ONE value definition!");
314 if (enumTypeDef.getQName() == null) {
315 throw new IllegalArgumentException("EnumTypeDefinition MUST contain NON-NULL QName!");
317 if (enumTypeDef.getQName().getLocalName() == null) {
318 throw new IllegalArgumentException("Local Name in EnumTypeDefinition QName cannot be NULL!");
320 if (typeBuilder == null) {
321 throw new IllegalArgumentException("Generated Type Builder reference cannot be NULL!");
324 final String enumerationName = parseToClassName(enumName);
325 final EnumBuilder enumBuilder = typeBuilder
326 .addEnumeration(enumerationName);
328 updateEnumPairsFromEnumTypeDef(enumTypeDef, enumBuilder);
333 private void updateEnumPairsFromEnumTypeDef(
334 final EnumTypeDefinition enumTypeDef, final EnumBuilder enumBuilder) {
335 if (enumBuilder != null) {
336 final List<EnumPair> enums = enumTypeDef.getValues();
339 for (final EnumPair enumPair : enums) {
340 if (enumPair != null) {
341 final String enumPairName = parseToClassName(enumPair
343 Integer enumPairValue = enumPair.getValue();
345 if (enumPairValue == null) {
346 enumPairValue = listIndex;
348 enumBuilder.addValue(enumPairName, enumPairValue);
356 private Type resolveTypeFromDataSchemaNode(final DataSchemaNode dataNode) {
357 Type returnType = null;
358 if (dataNode != null) {
359 if (dataNode instanceof LeafSchemaNode) {
360 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
361 returnType = javaTypeForSchemaDefinitionType(leaf.getType());
362 } else if (dataNode instanceof LeafListSchemaNode) {
363 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
364 returnType = javaTypeForSchemaDefinitionType(leafList.getType());
370 private void resolveTypeDefsFromContext() {
371 final Set<Module> modules = schemaContext.getModules();
372 if (modules == null) {
373 throw new IllegalArgumentException("Sef of Modules cannot be NULL!");
375 for (final Module module : modules) {
376 if (module == null) {
379 final String moduleName = module.getName();
380 final String basePackageName = moduleNamespaceToPackageName(module);
382 final Set<TypeDefinition<?>> typeDefinitions = module
383 .getTypeDefinitions();
385 final Map<String, Type> typeMap = new HashMap<>();
386 genTypeDefsContextMap.put(moduleName, typeMap);
388 if ((typeDefinitions != null) && (basePackageName != null)) {
389 for (final TypeDefinition<?> typedef : typeDefinitions) {
390 typedefToGeneratedType(basePackageName, moduleName, typedef);
392 final List<ExtendedType> extUnions = UnionDependencySort
393 .sort(typeDefinitions);
394 for (final ExtendedType extUnionType : extUnions) {
395 addUnionGeneratedTypeDefinition(basePackageName,
402 private Type typedefToGeneratedType(final String basePackageName,
403 final String moduleName, final TypeDefinition<?> typedef) {
404 if ((basePackageName != null) && (moduleName != null)
405 && (typedef != null) && (typedef.getQName() != null)) {
407 final String typedefName = typedef.getQName().getLocalName();
408 final TypeDefinition<?> baseTypeDefinition = baseTypeDefForExtendedType(typedef);
409 if (!(baseTypeDefinition instanceof LeafrefTypeDefinition)
410 && !(baseTypeDefinition instanceof IdentityrefTypeDefinition)) {
412 if (baseTypeDefinition instanceof EnumTypeDefinition) {
413 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDefinition;
414 returnType = resolveEnumFromTypeDefinition(enumTypeDef,
417 } else if (baseTypeDefinition instanceof BitsTypeDefinition) {
418 final BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) baseTypeDefinition;
419 returnType = bitsTypedefToTransferObject(bitsTypeDefinition,
420 basePackageName, typedefName);
423 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
424 .javaTypeForSchemaDefinitionType(baseTypeDefinition);
426 returnType = wrapJavaTypeIntoTO(basePackageName, typedef,
429 if (returnType != null) {
430 final Map<String, Type> typeMap = genTypeDefsContextMap
432 if (typeMap != null) {
433 typeMap.put(typedefName, returnType);
442 private GeneratedTransferObject wrapJavaTypeIntoTO(
443 final String basePackageName, final TypeDefinition<?> typedef,
444 final Type javaType) {
445 if (javaType != null) {
446 final String typedefName = typedef.getQName().getLocalName();
447 final String propertyName = parseToValidParamName(typedefName);
449 final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(
450 basePackageName, typedef);
452 final GeneratedPropertyBuilder genPropBuilder = genTOBuilder
453 .addProperty(propertyName);
455 genPropBuilder.setReturnType(javaType);
456 genTOBuilder.addEqualsIdentity(genPropBuilder);
457 genTOBuilder.addHashIdentity(genPropBuilder);
458 genTOBuilder.addToStringProperty(genPropBuilder);
459 return genTOBuilder.toInstance();
464 private void addUnionGeneratedTypeDefinition(final String basePackageName,
465 final TypeDefinition<?> typedef) {
466 if (basePackageName == null) {
467 throw new IllegalArgumentException("Base Package Name cannot be NULL!");
469 if (typedef == null) {
470 throw new IllegalArgumentException("Type Definition cannot be NULL!");
472 if (typedef.getQName() == null) {
473 throw new IllegalArgumentException("Type Definition cannot have non specified QName (QName cannot be NULL!)");
476 final TypeDefinition<?> baseTypeDefinition = typedef.getBaseType();
477 if ((baseTypeDefinition != null)
478 && (baseTypeDefinition instanceof UnionTypeDefinition)) {
479 final UnionTypeDefinition unionTypeDef = (UnionTypeDefinition) baseTypeDefinition;
480 final List<TypeDefinition<?>> unionTypes = unionTypeDef.getTypes();
481 final Module parentModule = findParentModuleForTypeDefinition(
482 schemaContext, typedef);
484 Map<String, Type> genTOsMap = null;
485 if (parentModule != null && parentModule.getName() != null) {
486 genTOsMap = genTypeDefsContextMap.get(parentModule.getName());
489 final GeneratedTOBuilder unionGenTransObject = typedefToTransferObject(
490 basePackageName, typedef);
491 if ((unionTypes != null) && (unionGenTransObject != null)) {
492 for (final TypeDefinition<?> unionType : unionTypes) {
493 final String typeName = unionType.getQName().getLocalName();
494 if (unionType instanceof ExtendedType) {
495 final Module unionTypeModule = findParentModuleForTypeDefinition(
496 schemaContext, unionType);
497 if (unionTypeModule != null
498 && unionTypeModule.getName() != null) {
499 final Map<String, Type> innerGenTOs = genTypeDefsContextMap
500 .get(unionTypeModule.getName());
502 final GeneratedTransferObject genTransferObject = (GeneratedTransferObject) innerGenTOs
504 if (genTransferObject != null) {
505 updateUnionTypeAsProperty(unionGenTransObject,
507 genTransferObject.getName());
510 } else if (unionType instanceof EnumTypeDefinition) {
511 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(
512 (EnumTypeDefinition) unionType, typeName,
513 unionGenTransObject);
514 final Type enumRefType = new ReferencedTypeImpl(
515 enumBuilder.getPackageName(),
516 enumBuilder.getName());
517 updateUnionTypeAsProperty(unionGenTransObject,
518 enumRefType, typeName);
520 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
521 .javaTypeForSchemaDefinitionType(unionType);
522 if (javaType != null) {
523 updateUnionTypeAsProperty(unionGenTransObject,
528 genTOsMap.put(typedef.getQName().getLocalName(),
529 unionGenTransObject.toInstance());
534 private void updateUnionTypeAsProperty(
535 final GeneratedTOBuilder unionGenTransObject, final Type type,
536 final String propertyName) {
537 if (unionGenTransObject != null && type != null) {
538 final GeneratedPropertyBuilder propBuilder = unionGenTransObject
539 .addProperty(parseToValidParamName(propertyName));
540 propBuilder.setReturnType(type);
541 propBuilder.setReadOnly(false);
543 if (!(type instanceof Enumeration)) {
544 unionGenTransObject.addEqualsIdentity(propBuilder);
545 unionGenTransObject.addHashIdentity(propBuilder);
546 unionGenTransObject.addToStringProperty(propBuilder);
551 private GeneratedTOBuilder typedefToTransferObject(
552 final String basePackageName, final TypeDefinition<?> typedef) {
554 final String packageName = packageNameForGeneratedType(basePackageName,
556 final String typeDefTOName = typedef.getQName().getLocalName();
558 if ((packageName != null) && (typedef != null)
559 && (typeDefTOName != null)) {
560 final String genTOName = parseToClassName(typeDefTOName);
561 final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(
562 packageName, genTOName);
569 private GeneratedTransferObject bitsTypedefToTransferObject(
570 final BitsTypeDefinition bitsTypeDefinition, final String basePackageName, final String typedefName) {
572 if (bitsTypeDefinition == null) {
573 throw new IllegalArgumentException("Bits TypeDefinition cannot be NULL!");
575 if (basePackageName == null) {
576 throw new IllegalArgumentException("Base Package Name cannot be NULL!");
578 if (typedefName == null) {
579 throw new IllegalArgumentException("Type Definition Local Name cannot be NULL!");
582 final String typeDefName = parseToClassName(typedefName);
583 final GeneratedTOBuilder genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeDefName);
585 final List<Bit> bitList = bitsTypeDefinition.getBits();
586 GeneratedPropertyBuilder genPropertyBuilder;
587 for (final Bit bit : bitList) {
588 String name = bit.getName();
589 genPropertyBuilder = genTOBuilder.addProperty(parseToValidParamName(name));
590 genPropertyBuilder.setReadOnly(false);
591 genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
593 genTOBuilder.addEqualsIdentity(genPropertyBuilder);
594 genTOBuilder.addHashIdentity(genPropertyBuilder);
595 genTOBuilder.addToStringProperty(genPropertyBuilder);
597 return genTOBuilder.toInstance();