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.apache.commons.lang.StringEscapeUtils;
11 import org.opendaylight.controller.binding.generator.util.ReferencedTypeImpl;
12 import org.opendaylight.controller.binding.generator.util.TypeConstants;
13 import org.opendaylight.controller.binding.generator.util.Types;
14 import org.opendaylight.controller.binding.generator.util.generated.type.builder.EnumerationBuilderImpl;
15 import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
16 import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;
17 import org.opendaylight.controller.sal.binding.model.api.Enumeration;
18 import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
19 import org.opendaylight.controller.sal.binding.model.api.Type;
20 import org.opendaylight.controller.sal.binding.model.api.type.builder.EnumBuilder;
21 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
22 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTOBuilder;
23 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
24 import org.opendaylight.controller.yang.common.QName;
25 import org.opendaylight.controller.yang.model.api.*;
26 import org.opendaylight.controller.yang.model.api.type.*;
27 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
28 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
29 import org.opendaylight.controller.yang.model.util.ExtendedType;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
37 import static org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil.*;
38 import static org.opendaylight.controller.yang.model.util.SchemaContextUtil.*;
40 public final class TypeProviderImpl implements TypeProvider {
42 private final SchemaContext schemaContext;
43 private Map<String, Map<String, Type>> genTypeDefsContextMap;
44 private final Map<SchemaPath, Type> referencedTypes;
46 public TypeProviderImpl(final SchemaContext schemaContext) {
47 if (schemaContext == null) {
48 throw new IllegalArgumentException("Schema Context cannot be null!");
51 this.schemaContext = schemaContext;
52 this.genTypeDefsContextMap = new HashMap<>();
53 this.referencedTypes = new HashMap<>();
54 resolveTypeDefsFromContext();
57 public void putReferencedType(final SchemaPath refTypePath,
59 if (refTypePath == null) {
60 throw new IllegalArgumentException("Path reference of "
61 + "Enumeration Type Definition cannot be NULL!");
64 if (refType == null) {
65 throw new IllegalArgumentException("Reference to Enumeration "
66 + "Type cannot be NULL!");
68 referencedTypes.put(refTypePath, refType);
74 * @see org.opendaylight.controller.yang.model.type.provider.TypeProvider#
75 * javaTypeForYangType(java.lang.String)
78 public Type javaTypeForYangType(String type) {
79 Type t = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
80 .javaTypeForYangType(type);
85 public Type javaTypeForSchemaDefinitionType(
86 final TypeDefinition<?> typeDefinition) {
87 Type returnType = null;
88 if (typeDefinition == null) {
89 throw new IllegalArgumentException("Type Definition cannot be NULL!");
91 if (typeDefinition.getQName() == null) {
92 throw new IllegalArgumentException("Type Definition cannot have non specified QName (QName cannot be NULL!)");
94 if (typeDefinition.getQName().getLocalName() == null) {
95 throw new IllegalArgumentException("Type Definitions Local Name cannot be NULL!");
97 final String typedefName = typeDefinition.getQName().getLocalName();
98 if (typeDefinition instanceof ExtendedType) {
99 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
101 if (baseTypeDef instanceof LeafrefTypeDefinition) {
102 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) baseTypeDef;
103 returnType = provideTypeForLeafref(leafref);
104 } else if (baseTypeDef instanceof IdentityrefTypeDefinition) {
105 final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) baseTypeDef;
106 returnType = returnTypeForIdentityref(idref);
107 } else if (baseTypeDef instanceof EnumTypeDefinition) {
108 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
109 returnType = resolveEnumFromTypeDefinition(enumTypeDef,
112 final Module module = findParentModuleForTypeDefinition(
113 schemaContext, typeDefinition);
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) {
131 final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) typeDefinition;
132 returnType = returnTypeForIdentityref(idref);
134 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
135 .javaTypeForSchemaDefinitionType(typeDefinition);
138 // TODO: add throw exception when we will be able to resolve ALL yang
140 // if (returnType == null) {
141 // throw new IllegalArgumentException("Type Provider can't resolve " +
142 // "type for specified Type Definition " + typedefName);
147 private Type returnTypeForIdentityref(IdentityrefTypeDefinition idref) {
148 QName baseIdQName = idref.getIdentity();
149 Module module = schemaContext.findModuleByNamespace(baseIdQName.getNamespace());
150 IdentitySchemaNode identity = null;
151 for (IdentitySchemaNode id : module.getIdentities()) {
152 if (id.getQName().equals(baseIdQName)) {
156 if (identity == null) {
157 throw new IllegalArgumentException("Target identity '" + baseIdQName + "' do not exists");
160 final String basePackageName = moduleNamespaceToPackageName(module);
161 final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
162 final String genTypeName = parseToClassName(identity.getQName().getLocalName());
164 Type baseType = Types.typeForClass(Class.class);
165 Type paramType = Types.wildcardTypeFor(packageName, genTypeName);
166 Type returnType = Types.parameterizedTypeFor(baseType, paramType);
170 public Type generatedTypeForExtendedDefinitionType(
171 final TypeDefinition<?> typeDefinition) {
172 Type returnType = null;
173 if (typeDefinition == null) {
174 throw new IllegalArgumentException("Type Definition cannot be NULL!");
176 if (typeDefinition.getQName() == null) {
177 throw new IllegalArgumentException("Type Definition cannot have non specified QName (QName cannot be NULL!)");
179 if (typeDefinition.getQName() == null) {
180 throw new IllegalArgumentException("Type Definitions Local Name cannot be NULL!");
183 final String typedefName = typeDefinition.getQName().getLocalName();
184 if (typeDefinition instanceof ExtendedType) {
185 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
187 if (!(baseTypeDef instanceof LeafrefTypeDefinition)
188 && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
189 final Module module = findParentModuleForTypeDefinition(
190 schemaContext, typeDefinition);
192 if (module != null) {
193 final Map<String, Type> genTOs = genTypeDefsContextMap
194 .get(module.getName());
195 if (genTOs != null) {
196 returnType = genTOs.get(typedefName);
204 private TypeDefinition<?> baseTypeDefForExtendedType(
205 final TypeDefinition<?> extendTypeDef) {
206 if (extendTypeDef == null) {
207 throw new IllegalArgumentException("Type Definiition reference cannot be NULL!");
209 final TypeDefinition<?> baseTypeDef = extendTypeDef.getBaseType();
210 if (baseTypeDef instanceof ExtendedType) {
211 return baseTypeDefForExtendedType(baseTypeDef);
218 public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType) {
219 Type returnType = null;
220 if (leafrefType == null) {
221 throw new IllegalArgumentException("Leafref Type Definition reference cannot be NULL!");
224 if (leafrefType.getPathStatement() == null) {
225 throw new IllegalArgumentException("The Path Statement for Leafref Type Definition cannot be NULL!");
228 final RevisionAwareXPath xpath = leafrefType.getPathStatement();
229 final String strXPath = xpath.toString();
231 if (strXPath != null) {
232 if (strXPath.matches(".*//[.* | .*//].*")) {
233 returnType = Types.typeForClass(Object.class);
235 final Module module = findParentModuleForTypeDefinition(
236 schemaContext, leafrefType);
237 if (module != null) {
238 final DataSchemaNode dataNode;
239 if (xpath.isAbsolute()) {
240 dataNode = findDataSchemaNode(schemaContext, module,
243 dataNode = findDataSchemaNodeForRelativeXPath(
244 schemaContext, module, leafrefType, xpath);
247 if (leafContainsEnumDefinition(dataNode)) {
248 returnType = referencedTypes.get(dataNode.getPath());
249 } else if (leafListContainsEnumDefinition(dataNode)) {
250 returnType = Types.listTypeFor(referencedTypes
251 .get(dataNode.getPath()));
253 returnType = resolveTypeFromDataSchemaNode(dataNode);
261 private boolean leafContainsEnumDefinition(final DataSchemaNode dataNode) {
262 if (dataNode instanceof LeafSchemaNode) {
263 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
264 if (leaf.getType() instanceof EnumTypeDefinition) {
271 private boolean leafListContainsEnumDefinition(final DataSchemaNode dataNode) {
272 if (dataNode instanceof LeafListSchemaNode) {
273 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
274 if (leafList.getType() instanceof EnumTypeDefinition) {
281 private Enumeration resolveEnumFromTypeDefinition(
282 final EnumTypeDefinition enumTypeDef, final String enumName) {
283 if (enumTypeDef == null) {
284 throw new IllegalArgumentException("EnumTypeDefinition reference cannot be NULL!");
286 if (enumTypeDef.getValues() == null) {
287 throw new IllegalArgumentException("EnumTypeDefinition MUST contain at least ONE value definition!");
289 if (enumTypeDef.getQName() == null) {
290 throw new IllegalArgumentException("EnumTypeDefinition MUST contain NON-NULL QName!");
292 if (enumTypeDef.getQName().getLocalName() == null) {
293 throw new IllegalArgumentException("Local Name in EnumTypeDefinition QName cannot be NULL!");
296 final String enumerationName = parseToClassName(enumName);
298 Module module = findParentModuleForTypeDefinition(schemaContext,
300 final String basePackageName = moduleNamespaceToPackageName(module);
302 final EnumBuilder enumBuilder = new EnumerationBuilderImpl(
303 basePackageName, enumerationName);
304 updateEnumPairsFromEnumTypeDef(enumTypeDef, enumBuilder);
305 return enumBuilder.toInstance(null);
308 private EnumBuilder resolveInnerEnumFromTypeDefinition(
309 final EnumTypeDefinition enumTypeDef, final String enumName,
310 final GeneratedTypeBuilder typeBuilder) {
311 if (enumTypeDef == null) {
312 throw new IllegalArgumentException("EnumTypeDefinition reference cannot be NULL!");
314 if (enumTypeDef.getValues() == null) {
315 throw new IllegalArgumentException("EnumTypeDefinition MUST contain at least ONE value definition!");
317 if (enumTypeDef.getQName() == null) {
318 throw new IllegalArgumentException("EnumTypeDefinition MUST contain NON-NULL QName!");
320 if (enumTypeDef.getQName().getLocalName() == null) {
321 throw new IllegalArgumentException("Local Name in EnumTypeDefinition QName cannot be NULL!");
323 if (typeBuilder == null) {
324 throw new IllegalArgumentException("Generated Type Builder reference cannot be NULL!");
327 final String enumerationName = parseToClassName(enumName);
328 final EnumBuilder enumBuilder = typeBuilder
329 .addEnumeration(enumerationName);
331 updateEnumPairsFromEnumTypeDef(enumTypeDef, enumBuilder);
336 private void updateEnumPairsFromEnumTypeDef(
337 final EnumTypeDefinition enumTypeDef, final EnumBuilder enumBuilder) {
338 if (enumBuilder != null) {
339 final List<EnumPair> enums = enumTypeDef.getValues();
342 for (final EnumPair enumPair : enums) {
343 if (enumPair != null) {
344 final String enumPairName = parseToClassName(enumPair
346 Integer enumPairValue = enumPair.getValue();
348 if (enumPairValue == null) {
349 enumPairValue = listIndex;
351 enumBuilder.addValue(enumPairName, enumPairValue);
359 private Type resolveTypeFromDataSchemaNode(final DataSchemaNode dataNode) {
360 Type returnType = null;
361 if (dataNode != null) {
362 if (dataNode instanceof LeafSchemaNode) {
363 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
364 returnType = javaTypeForSchemaDefinitionType(leaf.getType());
365 } else if (dataNode instanceof LeafListSchemaNode) {
366 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
367 returnType = javaTypeForSchemaDefinitionType(leafList.getType());
373 private void resolveTypeDefsFromContext() {
374 final Set<Module> modules = schemaContext.getModules();
375 if (modules == null) {
376 throw new IllegalArgumentException("Sef of Modules cannot be NULL!");
378 for (final Module module : modules) {
379 if (module == null) {
382 final String moduleName = module.getName();
383 final String basePackageName = moduleNamespaceToPackageName(module);
385 final Set<TypeDefinition<?>> typeDefinitions = module
386 .getTypeDefinitions();
388 final Map<String, Type> typeMap = new HashMap<>();
389 genTypeDefsContextMap.put(moduleName, typeMap);
391 if ((typeDefinitions != null) && (basePackageName != null)) {
392 for (final TypeDefinition<?> typedef : typeDefinitions) {
393 typedefToGeneratedType(basePackageName, moduleName, typedef);
395 final List<ExtendedType> extUnions = UnionDependencySort
396 .sort(typeDefinitions);
397 for (final ExtendedType extUnionType : extUnions) {
398 addUnionGeneratedTypeDefinition(basePackageName,
405 private Type typedefToGeneratedType(final String basePackageName,
406 final String moduleName, final TypeDefinition<?> typedef) {
407 if ((basePackageName != null) && (moduleName != null)
408 && (typedef != null) && (typedef.getQName() != null)) {
410 final String typedefName = typedef.getQName().getLocalName();
411 final TypeDefinition<?> baseTypeDefinition = baseTypeDefForExtendedType(typedef);
412 if (!(baseTypeDefinition instanceof LeafrefTypeDefinition)
413 && !(baseTypeDefinition instanceof IdentityrefTypeDefinition)) {
415 if (baseTypeDefinition instanceof EnumTypeDefinition) {
416 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDefinition;
417 returnType = resolveEnumFromTypeDefinition(enumTypeDef,
420 } else if (baseTypeDefinition instanceof BitsTypeDefinition) {
421 final BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) baseTypeDefinition;
422 returnType = bitsTypedefToTransferObject(bitsTypeDefinition,
423 basePackageName, typedefName);
426 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
427 .javaTypeForSchemaDefinitionType(baseTypeDefinition);
429 returnType = wrapJavaTypeIntoTO(basePackageName, typedef,
432 if (returnType != null) {
433 final Map<String, Type> typeMap = genTypeDefsContextMap
435 if (typeMap != null) {
436 typeMap.put(typedefName, returnType);
445 private GeneratedTransferObject wrapJavaTypeIntoTO(
446 final String basePackageName, final TypeDefinition<?> typedef,
447 final Type javaType) {
448 if (javaType != null) {
449 final String typedefName = typedef.getQName().getLocalName();
450 final String propertyName = parseToValidParamName(typedefName);
452 final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(
453 basePackageName, typedef);
455 final GeneratedPropertyBuilder genPropBuilder = genTOBuilder
456 .addProperty(propertyName);
458 genPropBuilder.setReturnType(javaType);
459 genTOBuilder.addEqualsIdentity(genPropBuilder);
460 genTOBuilder.addHashIdentity(genPropBuilder);
461 genTOBuilder.addToStringProperty(genPropBuilder);
462 if (javaType == BaseYangTypes.STRING_TYPE) {
463 if (typedef instanceof ExtendedType) {
464 List<PatternConstraint> patternConstraints = ((ExtendedType) typedef).getPatterns();
465 List<String> regularExpressions = new ArrayList<String>();
467 String modifiedRegEx;
468 for (PatternConstraint ptrnCons : patternConstraints) {
469 regEx = ptrnCons.getRegularExpression();
470 modifiedRegEx = StringEscapeUtils.escapeJava(regEx);
471 regularExpressions.add(modifiedRegEx);
474 genTOBuilder.addConstant(Types.listTypeFor(BaseYangTypes.STRING_TYPE),
475 TypeConstants.PATTERN_CONSTANT_NAME, regularExpressions);
479 return genTOBuilder.toInstance();
484 private void addUnionGeneratedTypeDefinition(final String basePackageName,
485 final TypeDefinition<?> typedef) {
486 if (basePackageName == null) {
487 throw new IllegalArgumentException("Base Package Name cannot be NULL!");
489 if (typedef == null) {
490 throw new IllegalArgumentException("Type Definition cannot be NULL!");
492 if (typedef.getQName() == null) {
493 throw new IllegalArgumentException("Type Definition cannot have non specified QName (QName cannot be NULL!)");
496 final TypeDefinition<?> baseTypeDefinition = typedef.getBaseType();
497 if ((baseTypeDefinition != null)
498 && (baseTypeDefinition instanceof UnionTypeDefinition)) {
499 final UnionTypeDefinition unionTypeDef = (UnionTypeDefinition) baseTypeDefinition;
500 final List<TypeDefinition<?>> unionTypes = unionTypeDef.getTypes();
501 final Module parentModule = findParentModuleForTypeDefinition(
502 schemaContext, typedef);
504 Map<String, Type> genTOsMap = null;
505 if (parentModule != null && parentModule.getName() != null) {
506 genTOsMap = genTypeDefsContextMap.get(parentModule.getName());
509 final GeneratedTOBuilder unionGenTransObject = typedefToTransferObject(
510 basePackageName, typedef);
511 if ((unionTypes != null) && (unionGenTransObject != null)) {
512 for (final TypeDefinition<?> unionType : unionTypes) {
513 final String typeName = unionType.getQName().getLocalName();
514 if (unionType instanceof ExtendedType) {
515 final Module unionTypeModule = findParentModuleForTypeDefinition(
516 schemaContext, unionType);
517 if (unionTypeModule != null
518 && unionTypeModule.getName() != null) {
519 final Map<String, Type> innerGenTOs = genTypeDefsContextMap
520 .get(unionTypeModule.getName());
522 final GeneratedTransferObject genTransferObject = (GeneratedTransferObject) innerGenTOs
524 if (genTransferObject != null) {
525 updateUnionTypeAsProperty(unionGenTransObject,
527 genTransferObject.getName());
530 } else if (unionType instanceof EnumTypeDefinition) {
531 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(
532 (EnumTypeDefinition) unionType, typeName,
533 unionGenTransObject);
534 final Type enumRefType = new ReferencedTypeImpl(
535 enumBuilder.getPackageName(),
536 enumBuilder.getName());
537 updateUnionTypeAsProperty(unionGenTransObject,
538 enumRefType, typeName);
540 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
541 .javaTypeForSchemaDefinitionType(unionType);
542 if (javaType != null) {
543 updateUnionTypeAsProperty(unionGenTransObject,
548 genTOsMap.put(typedef.getQName().getLocalName(),
549 unionGenTransObject.toInstance());
554 private void updateUnionTypeAsProperty(
555 final GeneratedTOBuilder unionGenTransObject, final Type type,
556 final String propertyName) {
557 if (unionGenTransObject != null && type != null) {
558 final GeneratedPropertyBuilder propBuilder = unionGenTransObject
559 .addProperty(parseToValidParamName(propertyName));
560 propBuilder.setReturnType(type);
561 propBuilder.setReadOnly(false);
563 if (!(type instanceof Enumeration)) {
564 unionGenTransObject.addEqualsIdentity(propBuilder);
565 unionGenTransObject.addHashIdentity(propBuilder);
566 unionGenTransObject.addToStringProperty(propBuilder);
571 private GeneratedTOBuilder typedefToTransferObject(
572 final String basePackageName, final TypeDefinition<?> typedef) {
574 final String packageName = packageNameForGeneratedType(basePackageName,
576 final String typeDefTOName = typedef.getQName().getLocalName();
578 if ((packageName != null) && (typedef != null)
579 && (typeDefTOName != null)) {
580 final String genTOName = parseToClassName(typeDefTOName);
581 final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(
582 packageName, genTOName);
589 private GeneratedTransferObject bitsTypedefToTransferObject(
590 final BitsTypeDefinition bitsTypeDefinition, final String basePackageName, final String typedefName) {
592 if (bitsTypeDefinition == null) {
593 throw new IllegalArgumentException("Bits TypeDefinition cannot be NULL!");
595 if (basePackageName == null) {
596 throw new IllegalArgumentException("Base Package Name cannot be NULL!");
598 if (typedefName == null) {
599 throw new IllegalArgumentException("Type Definition Local Name cannot be NULL!");
602 final String typeDefName = parseToClassName(typedefName);
603 final GeneratedTOBuilder genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeDefName);
605 final List<Bit> bitList = bitsTypeDefinition.getBits();
606 GeneratedPropertyBuilder genPropertyBuilder;
607 for (final Bit bit : bitList) {
608 String name = bit.getName();
609 genPropertyBuilder = genTOBuilder.addProperty(parseToValidParamName(name));
610 genPropertyBuilder.setReadOnly(false);
611 genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
613 genTOBuilder.addEqualsIdentity(genPropertyBuilder);
614 genTOBuilder.addHashIdentity(genPropertyBuilder);
615 genTOBuilder.addToStringProperty(genPropertyBuilder);
617 return genTOBuilder.toInstance();