/* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.yangtools.sal.binding.generator.impl; import static com.google.common.base.Preconditions.*; import static extension org.opendaylight.yangtools.binding.generator.util.Types.*; import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.*; import static org.opendaylight.yangtools.binding.generator.util.BindingTypes.*; import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.*; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Iterator import java.util.Collection import org.opendaylight.yangtools.binding.generator.util.BindingTypes; import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl; import org.opendaylight.yangtools.binding.generator.util.Types; import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl; import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTypeBuilderImpl; import org.opendaylight.yangtools.sal.binding.generator.api.BindingGenerator; import org.opendaylight.yangtools.sal.binding.generator.spi.TypeProvider; import org.opendaylight.yangtools.sal.binding.model.api.AccessModifier; import org.opendaylight.yangtools.sal.binding.model.api.Type; import org.opendaylight.yangtools.sal.binding.model.api.type.builder.EnumBuilder; import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder; import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder; import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSignatureBuilder; import org.opendaylight.yangtools.sal.binding.yang.types.GroupingDefinitionDependencySort; import org.opendaylight.yangtools.sal.binding.yang.types.TypeProviderImpl; import org.opendaylight.yangtools.yang.binding.RpcService; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; import org.opendaylight.yangtools.yang.model.api.ChoiceNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; import org.opendaylight.yangtools.yang.model.util.DataNodeIterator; import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; import org.opendaylight.yangtools.yang.model.util.UnionType; import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort import org.opendaylight.yangtools.yang.model.util.ExtendedType; import org.opendaylight.yangtools.yang.model.api.UsesNode import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext import org.opendaylight.yangtools.sal.binding.model.api.type.builder.AnnotationTypeBuilder import org.opendaylight.yangtools.yang.model.api.ModuleImport import org.opendaylight.yangtools.yang.binding.DataContainer import org.opendaylight.yangtools.yang.model.api.AugmentationTarget import org.opendaylight.yangtools.yang.model.api.NotificationDefinition import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil import org.opendaylight.yangtools.sal.binding.model.api.Restrictions import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedPropertyBuilder import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.binding.BindingMapping import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilderBase import com.google.common.collect.Sets import java.net.URI import java.util.Date public class BindingGeneratorImpl implements BindingGenerator { private final Map genCtx = new HashMap() /** * Outer key represents the package name. Outer value represents map of * all builders in the same package. Inner key represents the schema node * name (in JAVA class/interface name format). Inner value represents * instance of builder for schema node specified in key part. */ private Map> genTypeBuilders; /** * Provide methods for converting YANG types to JAVA types. */ private var TypeProvider typeProvider; /** * Holds reference to schema context to resolve data of augmented element * when creating augmentation builder */ private var SchemaContext schemaContext; /** * Constant with the concrete name of namespace. */ private val static String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext"; /** * Constant with the concrete name of identifier. */ private val static String AUGMENT_IDENTIFIER_NAME = "augment-identifier"; /** * Resolves generated types from context schema nodes of all * modules. * * Generated types are created for modules, groupings, types, containers, * lists, choices, augments, rpcs, notification, identities. * * @param context * schema context which contains data about all schema nodes * saved in modules * @return list of types (usually GeneratedType * GeneratedTransferObjectwhich are generated from * context data. * @throws IllegalArgumentException * if param context is null * @throws IllegalStateException * if context contain no modules */ override generateTypes(SchemaContext context) { checkArgument(context !== null, "Schema Context reference cannot be NULL."); checkState(context.modules !== null, "Schema Context does not contain defined modules."); schemaContext = context; typeProvider = new TypeProviderImpl(context); val Set modules = context.modules; return generateTypes(context, modules); } /** * Resolves generated types from context schema nodes only for * modules specified in modules * * Generated types are created for modules, groupings, types, containers, * lists, choices, augments, rpcs, notification, identities. * * @param context * schema context which contains data about all schema nodes * saved in modules * @param modules * set of modules for which schema nodes should be generated * types * @return list of types (usually GeneratedType or * GeneratedTransferObject) which: *
    *
  • are generated from context schema nodes and
  • *
  • are also part of some of the module in modules * set
  • . *
* @throws IllegalArgumentException *
    *
  • if param context is null or
  • *
  • if param modules is null
  • *
* @throws IllegalStateException * if context contain no modules */ override generateTypes(SchemaContext context, Set modules) { checkArgument(context !== null, "Schema Context reference cannot be NULL."); checkState(context.modules !== null, "Schema Context does not contain defined modules."); checkArgument(modules !== null, "Set of Modules cannot be NULL."); schemaContext = context; typeProvider = new TypeProviderImpl(context); val contextModules = ModuleDependencySort.sort(context.modules); genTypeBuilders = new HashMap(); for (contextModule : contextModules) { moduleToGenTypes(contextModule, context); } for (contextModule : contextModules) { allAugmentsToGenTypes(contextModule); } val List filteredGenTypes = new ArrayList(); for (Module m : modules) { filteredGenTypes.addAll(genCtx.get(m).generatedTypes); val Set additionalTypes = (typeProvider as TypeProviderImpl).additionalTypes.get(m) if (additionalTypes != null) { filteredGenTypes.addAll(additionalTypes) } } return filteredGenTypes; } private def void moduleToGenTypes(Module m, SchemaContext context) { genCtx.put(m, new ModuleContext) allTypeDefinitionsToGenTypes(m) groupingsToGenTypes(m, m.groupings) rpcMethodsToGenType(m) allIdentitiesToGenTypes(m, context) notificationsToGenType(m) if (!m.childNodes.isEmpty()) { val moduleType = moduleToDataType(m) genCtx.get(m).addModuleNode(moduleType) val basePackageName = moduleNamespaceToPackageName(m); resolveDataSchemaNodes(m, basePackageName, moduleType, moduleType, m.childNodes) } } /** * Converts all extended type definitions of module to the list of * Type objects. * * @param module * module from which is obtained set of type definitions * @throws IllegalArgumentException *
    *
  • if module equals null
  • *
  • if name of module equals null
  • *
  • if type definitions of module equal null
  • *
* */ private def void allTypeDefinitionsToGenTypes(Module module) { checkArgument(module !== null, "Module reference cannot be NULL."); checkArgument(module.name !== null, "Module name cannot be NULL."); val it = new DataNodeIterator(module); val List> typeDefinitions = it.allTypedefs; checkState(typeDefinitions !== null, '''Type Definitions for module «module.name» cannot be NULL.'''); for (TypeDefinition typedef : typeDefinitions) { if (typedef !== null) { val type = (typeProvider as TypeProviderImpl).generatedTypeForExtendedDefinitionType(typedef, typedef); if (type !== null) { genCtx.get(module).addTypedefType(typedef.path, type) } } } } private def GeneratedTypeBuilder processDataSchemaNode(Module module, String basePackageName, GeneratedTypeBuilder parent, GeneratedTypeBuilder childOf, DataSchemaNode node) { if (node.augmenting || node.addedByUses) { return null } val packageName = packageNameForGeneratedType(basePackageName, node.path) val genType = addDefaultInterfaceDefinition(packageName, node, childOf) if (node instanceof DataNodeContainer) { genCtx.get(module).addChildNodeType(node.path, genType) groupingsToGenTypes(module, (node as DataNodeContainer).groupings) processUsesAugments(node as DataNodeContainer, module) } return genType } private def void containerToGenType(Module module, String basePackageName, GeneratedTypeBuilder parent, GeneratedTypeBuilder childOf, ContainerSchemaNode node) { val genType = processDataSchemaNode(module, basePackageName, parent, childOf, node) if (genType != null) { constructGetter(parent, node.QName.localName, node.description, genType) resolveDataSchemaNodes(module, basePackageName, genType, genType, node.childNodes) } } private def void listToGenType(Module module, String basePackageName, GeneratedTypeBuilder parent, GeneratedTypeBuilder childOf, ListSchemaNode node) { val genType = processDataSchemaNode(module, basePackageName, parent, childOf, node) if (genType != null) { constructGetter(parent, node.QName.localName, node.description, Types.listTypeFor(genType)) val List listKeys = listKeys(node); val packageName = packageNameForGeneratedType(basePackageName, (node).path) val genTOBuilder = resolveListKeyTOBuilder(packageName, node); if (genTOBuilder !== null) { val identifierMarker = IDENTIFIER.parameterizedTypeFor(genType); val identifiableMarker = IDENTIFIABLE.parameterizedTypeFor(genTOBuilder); genTOBuilder.addImplementsType(identifierMarker); genType.addImplementsType(identifiableMarker); } for (schemaNode : node.childNodes) { if (!schemaNode.augmenting) { addSchemaNodeToListBuilders(basePackageName, schemaNode, genType, genTOBuilder, listKeys, module); } } // serialVersionUID if (genTOBuilder !== null) { val GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID"); prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder as GeneratedTOBuilderImpl))); genTOBuilder.setSUID(prop); } typeBuildersToGenTypes(module, genType, genTOBuilder); } } private def void processUsesAugments(DataNodeContainer node, Module module) { val basePackageName = moduleNamespaceToPackageName(module); for (usesNode : node.uses) { for (augment : usesNode.augmentations) { augmentationToGenTypes(basePackageName, augment, module, usesNode); processUsesAugments(augment, module); } } } /** * Converts all augmentation of the module to the list * Type objects. * * @param module * module from which is obtained list of all augmentation objects * to iterate over them * @throws IllegalArgumentException *
    *
  • if the module equals null
  • *
  • if the name of module equals null
  • *
  • if the set of child nodes equals null
  • *
* */ private def void allAugmentsToGenTypes(Module module) { checkArgument(module !== null, "Module reference cannot be NULL."); checkArgument(module.name !== null, "Module name cannot be NULL."); if (module.childNodes === null) { throw new IllegalArgumentException( "Reference to Set of Augmentation Definitions in module " + module.name + " cannot be NULL."); } val basePackageName = moduleNamespaceToPackageName(module); val List augmentations = resolveAugmentations(module); for (augment : augmentations) { augmentationToGenTypes(basePackageName, augment, module, null); } } /** * Returns list of AugmentationSchema objects. The objects are * sorted according to the length of their target path from the shortest to * the longest. * * @param module * module from which is obtained list of all augmentation objects * @return list of sorted AugmentationSchema objects obtained * from module * @throws IllegalArgumentException *
    *
  • if the module equals null
  • *
  • if the set of augmentation equals null
  • *
* */ private def List resolveAugmentations(Module module) { checkArgument(module !== null, "Module reference cannot be NULL."); checkState(module.augmentations !== null, "Augmentations Set cannot be NULL."); val Set augmentations = module.augmentations; val List sortedAugmentations = new ArrayList(augmentations); Collections.sort(sortedAugmentations, [ augSchema1, augSchema2 | if (augSchema1.targetPath.path.size() > augSchema2.targetPath.path.size()) { return 1; } else if (augSchema1.targetPath.path.size() < augSchema2.targetPath.path.size()) { return -1; } return 0; ]); return sortedAugmentations; } /** * Converts whole module to GeneratedType object. * Firstly is created the module builder object from which is vally * obtained reference to GeneratedType object. * * @param module * module from which are obtained the module name, child nodes, * uses and is derived package name * @return GeneratedType which is internal representation of * the module * @throws IllegalArgumentException * if the module equals null * */ private def GeneratedTypeBuilder moduleToDataType(Module module) { checkArgument(module !== null, "Module reference cannot be NULL."); val moduleDataTypeBuilder = moduleTypeBuilder(module, "Data"); addImplementedInterfaceFromUses(module, moduleDataTypeBuilder); moduleDataTypeBuilder.addImplementsType(DATA_ROOT); return moduleDataTypeBuilder; } /** * Converts all rpcs inputs and outputs substatements of the module * to the list of Type objects. In addition are to containers * and lists which belong to input or output also part of returning list. * * @param module * module from which is obtained set of all rpc objects to * iterate over them * @throws IllegalArgumentException *
    *
  • if the module equals null
  • *
  • if the name of module equals null
  • *
  • if the set of child nodes equals null
  • *
* */ private def void rpcMethodsToGenType(Module module) { checkArgument(module !== null, "Module reference cannot be NULL."); checkArgument(module.name !== null, "Module name cannot be NULL."); checkArgument(module.childNodes !== null, "Reference to Set of RPC Method Definitions in module " + module.name + " cannot be NULL."); val basePackageName = moduleNamespaceToPackageName(module); val Set rpcDefinitions = module.rpcs; if (rpcDefinitions.isEmpty()) { return; } val interfaceBuilder = moduleTypeBuilder(module, "Service"); interfaceBuilder.addImplementsType(Types.typeForClass(RpcService)); for (rpc : rpcDefinitions) { if (rpc !== null) { val rpcName = BindingMapping.getClassName(rpc.QName); val rpcMethodName = parseToValidParamName(rpcName); val method = interfaceBuilder.addMethod(rpcMethodName); val input = rpc.input; val output = rpc.output; if (input !== null) { val inType = addRawInterfaceDefinition(basePackageName, input, rpcName); addImplementedInterfaceFromUses(input, inType); inType.addImplementsType(DATA_OBJECT); inType.addImplementsType(augmentable(inType)); resolveDataSchemaNodes(module, basePackageName, inType, inType, input.childNodes); genCtx.get(module).addChildNodeType(input.path, inType) val inTypeInstance = inType.toInstance(); method.addParameter(inTypeInstance, "input"); } var Type outTypeInstance = VOID; if (output !== null) { val outType = addRawInterfaceDefinition(basePackageName, output, rpcName); addImplementedInterfaceFromUses(output, outType); outType.addImplementsType(DATA_OBJECT); outType.addImplementsType(augmentable(outType)); resolveDataSchemaNodes(module, basePackageName, outType, outType, output.childNodes); genCtx.get(module).addChildNodeType(output.path, outType) outTypeInstance = outType.toInstance(); } val rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult), outTypeInstance); method.setReturnType(Types.parameterizedTypeFor(FUTURE, rpcRes)); } } genCtx.get(module).addTopLevelNodeType(interfaceBuilder) } /** * Converts all notifications of the module to the list of * Type objects. In addition are to this list added containers * and lists which are part of this notification. * * @param module * module from which is obtained set of all notification objects * to iterate over them * @throws IllegalArgumentException *
    *
  • if the module equals null
  • *
  • if the name of module equals null
  • *
  • if the set of child nodes equals null
  • *
* */ private def void notificationsToGenType(Module module) { checkArgument(module !== null, "Module reference cannot be NULL."); checkArgument(module.name !== null, "Module name cannot be NULL."); if (module.childNodes === null) { throw new IllegalArgumentException( "Reference to Set of Notification Definitions in module " + module.name + " cannot be NULL."); } val notifications = module.notifications; if(notifications.empty) return; val listenerInterface = moduleTypeBuilder(module, "Listener"); listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER); val basePackageName = moduleNamespaceToPackageName(module); for (notification : notifications) { if (notification !== null) { processUsesAugments(notification, module); val notificationInterface = addDefaultInterfaceDefinition(basePackageName, notification, BindingTypes.DATA_OBJECT); notificationInterface.addImplementsType(NOTIFICATION); genCtx.get(module).addChildNodeType(notification.path, notificationInterface) // Notification object resolveDataSchemaNodes(module, basePackageName, notificationInterface, notificationInterface, notification.childNodes); listenerInterface.addMethod("on" + notificationInterface.name) // .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification"). setReturnType(Types.VOID); } } genCtx.get(module).addTopLevelNodeType(listenerInterface) } /** * Converts all identities of the module to the list of * Type objects. * * @param module * module from which is obtained set of all identity objects to * iterate over them * @param context * schema context only used as input parameter for method * {@link identityToGenType} * */ private def void allIdentitiesToGenTypes(Module module, SchemaContext context) { val Set schemaIdentities = module.identities; val basePackageName = moduleNamespaceToPackageName(module); if (schemaIdentities !== null && !schemaIdentities.isEmpty()) { for (identity : schemaIdentities) { identityToGenType(module, basePackageName, identity, context); } } } /** * Converts the identity object to GeneratedType. Firstly it is * created transport object builder. If identity contains base identity then * reference to base identity is added to superior identity as its extend. * If identity doesn't contain base identity then only reference to abstract * class {@link org.opendaylight.yangtools.yang.model.api.BaseIdentity * BaseIdentity} is added * * @param module current module * @param basePackageName * string contains the module package name * @param identity * IdentitySchemaNode which contains data about identity * @param context * SchemaContext which is used to get package and name * information about base of identity * */ private def void identityToGenType(Module module, String basePackageName, IdentitySchemaNode identity, SchemaContext context) { if (identity === null) { return; } val packageName = packageNameForGeneratedType(basePackageName, identity.path); val genTypeName = BindingMapping.getClassName(identity.QName); val newType = new GeneratedTOBuilderImpl(packageName, genTypeName); val baseIdentity = identity.baseIdentity; if (baseIdentity === null) { newType.setExtendsType(Types.baseIdentityTO); } else { val baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity); val returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule); val returnTypeName = BindingMapping.getClassName(baseIdentity.QName); val gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName).toInstance(); newType.setExtendsType(gto); } newType.setAbstract(true); val qname = identity.QName; newType.qnameConstant(BindingMapping.QNAME_STATIC_FIELD_NAME,qname); genCtx.get(module).addIdentityType(identity.QName,newType) } private static def qnameConstant(GeneratedTypeBuilderBase toBuilder, String constantName, QName name) { toBuilder.addConstant(QName.typeForClass,constantName,''' org.opendaylight.yangtools.yang.common.QName.create("«name.namespace»","«name.formattedRevision»","«name.localName»") '''); } /** * Converts all groupings of the module to the list of * Type objects. Firstly are groupings sorted according mutual * dependencies. At least dependent (independent) groupings are in the list * saved at first positions. For every grouping the record is added to map * {@link BindingGeneratorImpl#allGroupings allGroupings} * * @param module * current module * @param collection of groupings from which types will be generated * */ private def void groupingsToGenTypes(Module module, Collection groupings) { val basePackageName = moduleNamespaceToPackageName(module); val List groupingsSortedByDependencies = new GroupingDefinitionDependencySort().sort( groupings); for (grouping : groupingsSortedByDependencies) { groupingToGenType(basePackageName, grouping, module); } } /** * Converts individual grouping to GeneratedType. Firstly generated type * builder is created and every child node of grouping is resolved to the * method. * * @param basePackageName * string contains the module package name * @param grouping * GroupingDefinition which contains data about grouping * @param module current module * @return GeneratedType which is generated from grouping (object of type * GroupingDefinition) */ private def void groupingToGenType(String basePackageName, GroupingDefinition grouping, Module module) { val packageName = packageNameForGeneratedType(basePackageName, grouping.path); val genType = addDefaultInterfaceDefinition(packageName, grouping); genCtx.get(module).addGroupingType(grouping.path, genType) resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.childNodes); groupingsToGenTypes(module, grouping.groupings); processUsesAugments(grouping, module); } /** * Tries to find EnumTypeDefinition in typeDefinition. If base * type of typeDefinition is of the type ExtendedType then this * method is recursively called with this base type. * * @param typeDefinition * TypeDefinition in which should be EnumTypeDefinition found as * base type * @return EnumTypeDefinition if it is found inside * typeDefinition or null in other case */ private def EnumTypeDefinition enumTypeDefFromExtendedType(TypeDefinition typeDefinition) { if (typeDefinition !== null) { if (typeDefinition.baseType instanceof EnumTypeDefinition) { return typeDefinition.baseType as EnumTypeDefinition; } else if (typeDefinition.baseType instanceof ExtendedType) { return enumTypeDefFromExtendedType(typeDefinition.baseType); } } return null; } /** * Adds enumeration builder created from enumTypeDef to * typeBuilder. * * Each enumTypeDef item is added to builder with its name and * value. * * @param enumTypeDef * EnumTypeDefinition contains enum data * @param enumName * string contains name which will be assigned to enumeration * builder * @param typeBuilder * GeneratedTypeBuilder to which will be enum builder assigned * @return enumeration builder which contains data from * enumTypeDef */ private def EnumBuilder resolveInnerEnumFromTypeDefinition(EnumTypeDefinition enumTypeDef, QName enumName, GeneratedTypeBuilder typeBuilder) { if ((enumTypeDef !== null) && (typeBuilder !== null) && (enumTypeDef.QName !== null) && (enumTypeDef.QName.localName !== null)) { val enumerationName = BindingMapping.getClassName(enumName); val enumBuilder = typeBuilder.addEnumeration(enumerationName); enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef); return enumBuilder; } return null; } /** * Generates type builder for module. * * @param module * Module which is source of package name for generated type * builder * @param postfix * string which is added to the module class name representation * as suffix * @return instance of GeneratedTypeBuilder which represents * module. * @throws IllegalArgumentException * if module equals null */ private def GeneratedTypeBuilder moduleTypeBuilder(Module module, String postfix) { checkArgument(module !== null, "Module reference cannot be NULL."); val packageName = moduleNamespaceToPackageName(module); val moduleName = BindingMapping.getClassName(module.name) + postfix; return new GeneratedTypeBuilderImpl(packageName, moduleName); } /** * Converts augSchema to list of Type which * contains generated type for augmentation. In addition there are also * generated types for all containers, list and choices which are child of * augSchema node or a generated types for cases are added if * augmented node is choice. * * @param augmentPackageName * string with the name of the package to which the augmentation * belongs * @param augSchema * AugmentationSchema which is contains data about augmentation * (target path, childs...) * @param module current module * @param parentUsesNode parent uses node of this augment (can be null if this augment is not defined under uses statement) * @throws IllegalArgumentException *
    *
  • if augmentPackageName equals null
  • *
  • if augSchema equals null
  • *
  • if target path of augSchema equals null
  • *
*/ private def void augmentationToGenTypes(String augmentPackageName, AugmentationSchema augSchema, Module module, UsesNode parentUsesNode) { checkArgument(augmentPackageName !== null, "Package Name cannot be NULL."); checkArgument(augSchema !== null, "Augmentation Schema cannot be NULL."); checkState(augSchema.targetPath !== null, "Augmentation Schema does not contain Target Path (Target Path is NULL)."); processUsesAugments(augSchema, module); val targetPath = augSchema.targetPath; var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath); if (targetSchemaNode instanceof DataSchemaNode && (targetSchemaNode as DataSchemaNode).isAddedByUses()) { if (parentUsesNode == null) { targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode); } else { targetSchemaNode = findOriginalTargetFromGrouping(targetSchemaNode.QName.localName, parentUsesNode); } if (targetSchemaNode == null) { throw new NullPointerException( "Failed to find target node from grouping for augmentation " + augSchema + " in module " + module.name); } } if (targetSchemaNode == null) { throw new IllegalArgumentException("augment target not found") } if (targetSchemaNode !== null) { var targetTypeBuilder = findChildNodeByPath(targetSchemaNode.path) if (targetTypeBuilder === null) { targetTypeBuilder = findCaseByPath(targetSchemaNode.path) } if (targetTypeBuilder === null) { throw new NullPointerException("Target type not yet generated: " + targetSchemaNode); } if (!(targetSchemaNode instanceof ChoiceNode)) { var packageName = augmentPackageName; if (parentUsesNode != null) { packageName = packageNameForGeneratedType(augmentPackageName, augSchema.targetPath); } val augTypeBuilder = addRawAugmentGenTypeDefinition(module, packageName, augmentPackageName, targetTypeBuilder.toInstance, augSchema); genCtx.get(module).addAugmentType(augTypeBuilder) genCtx.get(module).addTypeToAugmentation(augTypeBuilder,augSchema); } else { generateTypesFromAugmentedChoiceCases(module, augmentPackageName, targetTypeBuilder.toInstance, targetSchemaNode as ChoiceNode, augSchema.childNodes); } } } /** * Utility method which search for original node defined in grouping. */ private def DataSchemaNode findOriginal(DataSchemaNode node) { var DataSchemaNode result = findCorrectTargetFromGrouping(node); if (result == null) { result = findCorrectTargetFromAugment(node); if (result != null) { if (result.addedByUses) { result = findOriginal(result); } } } return result; } private def DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node) { if (!node.augmenting) { return null } var String currentName = node.QName.localName var Object currentNode = node var Object parent = node; val tmpPath = new ArrayList() val tmpTree = new ArrayList() var AugmentationSchema augment = null; do { val SchemaPath sp = (parent as SchemaNode).path val List names = sp.path val List newNames = new ArrayList(names) newNames.remove(newNames.size - 1) val SchemaPath newSp = new SchemaPath(newNames, sp.absolute) parent = findDataSchemaNode(schemaContext, newSp) if (parent instanceof AugmentationTarget) { tmpPath.add(currentName); tmpTree.add(currentNode as SchemaNode) augment = findNodeInAugment((parent as AugmentationTarget).availableAugmentations, currentName); if (augment == null) { currentName = (parent as DataSchemaNode).QName.localName; currentNode = parent } } } while ((parent as DataSchemaNode).augmenting && augment == null); if (augment == null) { return null; } else { Collections.reverse(tmpPath); Collections.reverse(tmpTree); var Object actualParent = augment; var DataSchemaNode result = null; for (name : tmpPath) { if (actualParent instanceof DataNodeContainer) { result = (actualParent as DataNodeContainer).getDataChildByName(name); actualParent = (actualParent as DataNodeContainer).getDataChildByName(name); } else { if (actualParent instanceof ChoiceNode) { result = (actualParent as ChoiceNode).getCaseNodeByName(name); actualParent = (actualParent as ChoiceNode).getCaseNodeByName(name); } } } if (result.addedByUses) { result = findCorrectTargetFromAugmentGrouping(result, augment, tmpTree); } return result; } } private def AugmentationSchema findNodeInAugment(Collection augments, String name) { for (augment : augments) { if (augment.getDataChildByName(name) != null) { return augment; } } return null; } private def DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node) { if (node.path.path.size == 1) { // uses is under module statement val Module m = findParentModule(schemaContext, node); var DataSchemaNode result = null; for (u : m.uses) { var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path); if (!(targetGrouping instanceof GroupingDefinition)) { throw new IllegalArgumentException("Failed to generate code for augment in " + u); } var gr = targetGrouping as GroupingDefinition; result = gr.getDataChildByName(node.QName.localName); } if (result == null) { throw new IllegalArgumentException("Failed to generate code for augment") } return result } else { var DataSchemaNode result = null; var String currentName = node.QName.localName var tmpPath = new ArrayList() var Object parent = null val SchemaPath sp = node.path val List names = sp.path val List newNames = new ArrayList(names) newNames.remove(newNames.size - 1) val SchemaPath newSp = new SchemaPath(newNames, sp.absolute) parent = findDataSchemaNode(schemaContext, newSp) do { tmpPath.add(currentName); val dataNodeParent = parent as DataNodeContainer; for (u : dataNodeParent.uses) { if (result == null) { result = getResultFromUses(u, currentName) } } if (result == null) { currentName = (parent as SchemaNode).QName.localName if (parent instanceof DataSchemaNode) { val SchemaPath nodeSp = (parent as DataSchemaNode).path val List nodeNames = nodeSp.path val List nodeNewNames = new ArrayList(nodeNames) nodeNewNames.remove(nodeNewNames.size - 1) if (nodeNewNames.empty) { parent = getParentModule(parent as SchemaNode) } else { val SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.absolute) parent = findDataSchemaNode(schemaContext, nodeNewSp) } } else { throw new IllegalArgumentException("Failed to generate code for augment") } } } while (result == null && !(parent instanceof Module)); if (result != null) { result = getTargetNode(tmpPath, result) } return result; } } private def DataSchemaNode findCorrectTargetFromAugmentGrouping(DataSchemaNode node, AugmentationSchema parentNode, List dataTree) { var DataSchemaNode result = null; var String currentName = node.QName.localName var tmpPath = new ArrayList() tmpPath.add(currentName) var int i = 1; var Object parent = null do { if (dataTree.size < 2 || dataTree.size == i) { parent = parentNode } else { parent = dataTree.get(dataTree.size - (i+1)) tmpPath.add((parent as SchemaNode).QName.localName); } val dataNodeParent = parent as DataNodeContainer; for (u : dataNodeParent.uses) { if (result == null) { result = getResultFromUses(u, currentName) } } if (result == null) { i = i + 1 currentName = (parent as SchemaNode).QName.localName } } while (result == null); if (result != null) { result = getTargetNode(tmpPath, result) } return result; } private def getResultFromUses(UsesNode u, String currentName) { var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path) if (!(targetGrouping instanceof GroupingDefinition)) { throw new IllegalArgumentException("Failed to generate code for augment in " + u) } var gr = targetGrouping as GroupingDefinition return gr.getDataChildByName(currentName) } private def getTargetNode(List tmpPath, DataSchemaNode node) { var DataSchemaNode result = node if (tmpPath.size == 1) { if (result != null && result.addedByUses) { result = findOriginal(result); } return result; } else { var DataSchemaNode newParent = result; Collections.reverse(tmpPath); tmpPath.remove(0); for (name : tmpPath) { newParent = (newParent as DataNodeContainer).getDataChildByName(name); } if (newParent != null && newParent.addedByUses) { newParent = findOriginal(newParent); } return newParent; } } /** * Convenient method to find node added by uses statement. */ private def DataSchemaNode findOriginalTargetFromGrouping(String targetSchemaNodeName, UsesNode parentUsesNode) { var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, parentUsesNode.groupingPath.path); if (!(targetGrouping instanceof GroupingDefinition)) { throw new IllegalArgumentException("Failed to generate code for augment in " + parentUsesNode); } var grouping = targetGrouping as GroupingDefinition; var result = grouping.getDataChildByName(targetSchemaNodeName); if (result == null) { return null; } var boolean fromUses = result.addedByUses; var Iterator groupingUses = grouping.uses.iterator; while (fromUses) { if (groupingUses.hasNext()) { grouping = findNodeInSchemaContext(schemaContext, groupingUses.next().groupingPath.path) as GroupingDefinition; result = grouping.getDataChildByName(targetSchemaNodeName); fromUses = result.addedByUses; } else { throw new NullPointerException("Failed to generate code for augment in " + parentUsesNode); } } return result; } /** * Returns a generated type builder for an augmentation. * * The name of the type builder is equal to the name of augmented node with * serial number as suffix. * * @param module current module * @param augmentPackageName * string with contains the package name to which the augment * belongs * @param basePackageName * string with the package name to which the augmented node * belongs * @param targetTypeRef * target type * @param augSchema * augmentation schema which contains data about the child nodes * and uses of augment * @return generated type builder for augment */ private def GeneratedTypeBuilder addRawAugmentGenTypeDefinition(Module module, String augmentPackageName, String basePackageName, Type targetTypeRef, AugmentationSchema augSchema) { var Map augmentBuilders = genTypeBuilders.get(augmentPackageName); if (augmentBuilders === null) { augmentBuilders = new HashMap(); genTypeBuilders.put(augmentPackageName, augmentBuilders); } val augIdentifier = getAugmentIdentifier(augSchema.unknownSchemaNodes); val augTypeName = if (augIdentifier !== null) { BindingMapping.getClassName(augIdentifier) } else { augGenTypeName(augmentBuilders, targetTypeRef.name); } val augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName); augTypeBuilder.addImplementsType(DATA_OBJECT); augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef)); addImplementedInterfaceFromUses(augSchema, augTypeBuilder); augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema.childNodes); augmentBuilders.put(augTypeName, augTypeBuilder); return augTypeBuilder; } /** * * @param unknownSchemaNodes * @return nodeParameter of UnknownSchemaNode */ private def String getAugmentIdentifier(List unknownSchemaNodes) { for (unknownSchemaNode : unknownSchemaNodes) { val nodeType = unknownSchemaNode.nodeType; if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.localName) && YANG_EXT_NAMESPACE.equals(nodeType.namespace.toString())) { return unknownSchemaNode.nodeParameter; } } return null; } /** * Returns first unique name for the augment generated type builder. The * generated type builder name for augment consists from name of augmented * node and serial number of its augmentation. * * @param builders * map of builders which were created in the package to which the * augmentation belongs * @param genTypeName * string with name of augmented node * @return string with unique name for augmentation builder */ private def String augGenTypeName(Map builders, String genTypeName) { var index = 1; while ((builders !== null) && builders.containsKey(genTypeName + index)) { index = index + 1; } return genTypeName + index; } /** * Adds the methods to typeBuilder which represent subnodes of * node for which typeBuilder was created. * * The subnodes aren't mapped to the methods if they are part of grouping or * augment (in this case are already part of them). * * @param module current module * @param basePackageName * string contains the module package name * @param parent * generated type builder which represents any node. The subnodes * of this node are added to the typeBuilder as * methods. The subnode can be of type leaf, leaf-list, list, * container, choice. * @param childOf parent type * @param schemaNodes * set of data schema nodes which are the children of the node * for which typeBuilder was created * @return generated type builder which is the same builder as input * parameter. The getter methods (representing child nodes) could be * added to it. */ private def GeneratedTypeBuilder resolveDataSchemaNodes(Module module, String basePackageName, GeneratedTypeBuilder parent, GeneratedTypeBuilder childOf, Set schemaNodes) { if ((schemaNodes !== null) && (parent !== null)) { for (schemaNode : schemaNodes) { if (!schemaNode.augmenting && !schemaNode.addedByUses) { addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module); } } } return parent; } /** * Adds the methods to typeBuilder what represents subnodes of * node for which typeBuilder was created. * * @param module current module * @param basePackageName * string contains the module package name * @param typeBuilder * generated type builder which represents any node. The subnodes * of this node are added to the typeBuilder as * methods. The subnode can be of type leaf, leaf-list, list, * container, choice. * @param childOf parent type * @param schemaNodes * set of data schema nodes which are the children of the node * for which typeBuilder was created * @return generated type builder which is the same object as the input * parameter typeBuilder. The getter method could be * added to it. */ private def GeneratedTypeBuilder augSchemaNodeToMethods(Module module, String basePackageName, GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Set schemaNodes) { if ((schemaNodes !== null) && (typeBuilder !== null)) { for (schemaNode : schemaNodes) { if (!schemaNode.isAugmenting()) { addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module); } } } return typeBuilder; } /** * Adds to typeBuilder a method which is derived from * schemaNode. * * @param basePackageName * string with the module package name * @param node * data schema node which is added to typeBuilder as * a method * @param typeBuilder * generated type builder to which is schemaNode * added as a method. * @param childOf parent type * @param module current module */ private def void addSchemaNodeToBuilderAsMethod(String basePackageName, DataSchemaNode node, GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Module module) { if (node !== null && typeBuilder !== null) { switch (node) { case node instanceof LeafSchemaNode: resolveLeafSchemaNodeAsMethod(typeBuilder, node as LeafSchemaNode) case node instanceof LeafListSchemaNode: resolveLeafListSchemaNode(typeBuilder, node as LeafListSchemaNode) case node instanceof ContainerSchemaNode: containerToGenType(module, basePackageName, typeBuilder, childOf, node as ContainerSchemaNode) case node instanceof ListSchemaNode: listToGenType(module, basePackageName, typeBuilder, childOf, node as ListSchemaNode) case node instanceof ChoiceNode: choiceToGeneratedType(module, basePackageName, typeBuilder, node as ChoiceNode) } } } /** * Converts choiceNode to the list of generated types for * choice and its cases. * * The package names for choice and for its cases are created as * concatenation of the module package (basePackageName) and * names of all parents node. * * @param module current module * @param basePackageName * string with the module package name * @param parent parent type * @param childOf concrete parent for case child nodes * @param choiceNode * choice node which is mapped to generated type. Also child * nodes - cases are mapped to generated types. * @throws IllegalArgumentException *
    *
  • if basePackageName equals null
  • *
  • if choiceNode equals null
  • *
* */ private def void choiceToGeneratedType(Module module, String basePackageName, GeneratedTypeBuilder parent, ChoiceNode choiceNode) { checkArgument(basePackageName !== null, "Base Package Name cannot be NULL."); checkArgument(choiceNode !== null, "Choice Schema Node cannot be NULL."); if (!choiceNode.addedByUses) { val packageName = packageNameForGeneratedType(basePackageName, choiceNode.path); val choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode); constructGetter(parent, choiceNode.QName.localName, choiceNode.description, choiceTypeBuilder); choiceTypeBuilder.addImplementsType(DataContainer.typeForClass); genCtx.get(module).addChildNodeType(choiceNode.path, choiceTypeBuilder) generateTypesFromChoiceCases(module, basePackageName, parent, choiceTypeBuilder.toInstance, choiceNode); } } /** * Converts caseNodes set to list of corresponding generated * types. * * For every case which isn't added through augment or uses is * created generated type builder. The package names for the builder is * created as concatenation of the module package ( * basePackageName) and names of all parents nodes of the * concrete case. There is also relation "implements type" * between every case builder and choice type * * @param basePackageName * string with the module package name * @param refChoiceType * type which represents superior case * @param caseNodes * set of choice case nodes which are mapped to generated types * @return list of generated types for caseNodes. * @throws IllegalArgumentException *
    *
  • if basePackageName equals null
  • *
  • if refChoiceType equals null
  • *
  • if caseNodes equals null
  • *
* * */ private def void generateTypesFromChoiceCases(Module module, String basePackageName, GeneratedTypeBuilder choiceParent, Type refChoiceType, ChoiceNode choiceNode) { checkArgument(basePackageName !== null, "Base Package Name cannot be NULL."); checkArgument(refChoiceType !== null, "Referenced Choice Type cannot be NULL."); checkArgument(choiceNode !== null, "ChoiceNode cannot be NULL."); val Set caseNodes = choiceNode.cases; if (caseNodes == null) { return } for (caseNode : caseNodes) { if (caseNode !== null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) { val packageName = packageNameForGeneratedType(basePackageName, caseNode.path) val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode) caseTypeBuilder.addImplementsType(refChoiceType) genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder) val Set caseChildNodes = caseNode.childNodes if (caseChildNodes !== null) { var Object parentNode = null val SchemaPath nodeSp = choiceNode.path val List nodeNames = nodeSp.path val List nodeNewNames = new ArrayList(nodeNames) nodeNewNames.remove(nodeNewNames.size - 1) val SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.absolute) parentNode = findDataSchemaNode(schemaContext, nodeNewSp) var SchemaNode parent if (parentNode instanceof AugmentationSchema) { val augSchema = parentNode as AugmentationSchema; val targetPath = augSchema.targetPath; var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath) if (targetSchemaNode instanceof DataSchemaNode && (targetSchemaNode as DataSchemaNode).isAddedByUses()) { targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode); if (targetSchemaNode == null) { throw new NullPointerException( "Failed to find target node from grouping for augmentation " + augSchema + " in module " + module.name); } } parent = targetSchemaNode } else { val SchemaPath sp = choiceNode.path val List names = sp.path val List newNames = new ArrayList(names) newNames.remove(newNames.size - 1) val SchemaPath newSp = new SchemaPath(newNames, sp.absolute) parent = findDataSchemaNode(schemaContext, newSp) } var GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.path) resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes) } } processUsesAugments(caseNode, module); } } /** * Generates list of generated types for all the cases of a choice which are * added to the choice through the augment. * * * @param basePackageName * string contains name of package to which augment belongs. If * an augmented choice is from an other package (pcg1) than an * augmenting choice (pcg2) then case's of the augmenting choice * will belong to pcg2. * @param refChoiceType * Type which represents the choice to which case belongs. Every * case has to contain its choice in extend part. * @param caseNodes * set of choice case nodes for which is checked if are/aren't * added to choice through augmentation * @return list of generated types which represents augmented cases of * choice refChoiceType * @throws IllegalArgumentException *
    *
  • if basePackageName equals null
  • *
  • if refChoiceType equals null
  • *
  • if caseNodes equals null
  • *
*/ private def void generateTypesFromAugmentedChoiceCases(Module module, String basePackageName, Type targetType, ChoiceNode targetNode, Set augmentedNodes) { checkArgument(basePackageName !== null, "Base Package Name cannot be NULL."); checkArgument(targetType !== null, "Referenced Choice Type cannot be NULL."); checkArgument(augmentedNodes !== null, "Set of Choice Case Nodes cannot be NULL."); for (caseNode : augmentedNodes) { if (caseNode !== null) { val packageName = packageNameForGeneratedType(basePackageName, caseNode.path); val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode); caseTypeBuilder.addImplementsType(targetType); var SchemaNode parent = null val SchemaPath nodeSp = targetNode.path val List nodeNames = nodeSp.path val List nodeNewNames = new ArrayList(nodeNames) nodeNewNames.remove(nodeNewNames.size - 1) val SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.absolute) parent = findDataSchemaNode(schemaContext, nodeNewSp) var GeneratedTypeBuilder childOfType = null; if (parent instanceof Module) { childOfType = genCtx.get(parent as Module).moduleNode } else if (parent instanceof ChoiceCaseNode) { childOfType = findCaseByPath(parent.path) } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) { childOfType = findChildNodeByPath(parent.path) } else if (parent instanceof GroupingDefinition) { childOfType = findGroupingByPath(parent.path); } if (childOfType == null) { throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode); } if (caseNode instanceof DataNodeContainer) { val DataNodeContainer dataNodeCase = caseNode as DataNodeContainer; val Set childNodes = dataNodeCase.childNodes; if (childNodes !== null) { resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes); } } else { val ChoiceCaseNode node = targetNode.getCaseNodeByName(caseNode.getQName().getLocalName()); val Set childNodes = node.childNodes; if (childNodes !== null) { resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes); } } genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder) } } } /** * Converts leaf to the getter method which is added to * typeBuilder. * * @param typeBuilder * generated type builder to which is added getter method as * leaf mapping * @param leaf * leaf schema node which is mapped as getter method which is * added to typeBuilder * @return boolean value *
    *
  • false - if leaf or typeBuilder are * null
  • *
  • true - in other cases
  • *
*/ private def boolean resolveLeafSchemaNodeAsMethod(GeneratedTypeBuilder typeBuilder, LeafSchemaNode leaf) { if ((leaf !== null) && (typeBuilder !== null)) { val leafName = leaf.QName.localName; var String leafDesc = leaf.description; if (leafDesc === null) { leafDesc = ""; } val parentModule = findParentModule(schemaContext, leaf); if (leafName !== null && !leaf.isAddedByUses()) { val TypeDefinition typeDef = leaf.type; var Type returnType = null; var GeneratedTOBuilder genTOBuilder; if (typeDef instanceof EnumTypeDefinition) { returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf); val enumTypeDef = typeDef as EnumTypeDefinition; val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.QName, typeBuilder); if (enumBuilder !== null) { returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name); } (typeProvider as TypeProviderImpl).putReferencedType(leaf.path, returnType); } else if (typeDef instanceof UnionType) { genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule); if (genTOBuilder !== null) { returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule) } } else if (typeDef instanceof BitsTypeDefinition) { genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule); if (genTOBuilder !== null) { returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name); } } else { val Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef); returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions); } if (returnType !== null) { val MethodSignatureBuilder getter = constructGetter(typeBuilder, leafName, leafDesc, returnType); processContextRefExtension(leaf, getter, parentModule); return true; } } } return false; } private def void processContextRefExtension(LeafSchemaNode leaf, MethodSignatureBuilder getter, Module module) { for (node : leaf.unknownSchemaNodes) { val nodeType = node.nodeType; if ("context-reference".equals(nodeType.localName)) { val nodeParam = node.nodeParameter; var IdentitySchemaNode identity = null; var String basePackageName = null; val String[] splittedElement = nodeParam.split(":"); if (splittedElement.length == 1) { identity = findIdentityByName(module.identities, splittedElement.get(0)); basePackageName = moduleNamespaceToPackageName(module); } else if (splittedElement.length == 2) { var prefix = splittedElement.get(0); val Module dependentModule = findModuleFromImports(module.imports, prefix) if (dependentModule == null) { throw new IllegalArgumentException( "Failed to process context-reference: unknown prefix " + prefix); } identity = findIdentityByName(dependentModule.identities, splittedElement.get(1)); basePackageName = moduleNamespaceToPackageName(dependentModule); } else { throw new IllegalArgumentException( "Failed to process context-reference: unknown identity " + nodeParam); } if (identity == null) { throw new IllegalArgumentException( "Failed to process context-reference: unknown identity " + nodeParam); } val Class clazz = typeof(RoutingContext); val AnnotationTypeBuilder rc = getter.addAnnotation(clazz.package.name, clazz.simpleName); val packageName = packageNameForGeneratedType(basePackageName, identity.path); val genTypeName = BindingMapping.getClassName(identity.QName.localName); rc.addParameter("value", packageName + "." + genTypeName + ".class"); } } } private def IdentitySchemaNode findIdentityByName(Set identities, String name) { for (id : identities) { if (id.QName.localName.equals(name)) { return id; } } return null; } private def Module findModuleFromImports(Set imports, String prefix) { for (imp : imports) { if (imp.prefix.equals(prefix)) { return schemaContext.findModuleByName(imp.moduleName, imp.revision); } } return null; } /** * Converts leaf schema node to property of generated TO * builder. * * @param toBuilder * generated TO builder to which is leaf added as * property * @param leaf * leaf schema node which is added to toBuilder as * property * @param isReadOnly * boolean value which says if leaf property is|isn't read only * @return boolean value *
    *
  • false - if leaf, toBuilder or leaf * name equals null or if leaf is added by uses.
  • *
  • true - other cases
  • *
*/ private def boolean resolveLeafSchemaNodeAsProperty(GeneratedTOBuilder toBuilder, LeafSchemaNode leaf, boolean isReadOnly) { if ((leaf !== null) && (toBuilder !== null)) { val leafName = leaf.QName.localName; var String leafDesc = leaf.description; if (leafDesc === null) { leafDesc = ""; } if (leafName !== null) { val TypeDefinition typeDef = leaf.type; // TODO: properly resolve enum types val returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf); if (returnType !== null) { val propBuilder = toBuilder.addProperty(parseToValidParamName(leafName)); propBuilder.setReadOnly(isReadOnly); propBuilder.setReturnType(returnType); propBuilder.setComment(leafDesc); toBuilder.addEqualsIdentity(propBuilder); toBuilder.addHashIdentity(propBuilder); toBuilder.addToStringProperty(propBuilder); return true; } } } return false; } /** * Converts node leaf list schema node to getter method of * typeBuilder. * * @param typeBuilder * generated type builder to which is node added as * getter method * @param node * leaf list schema node which is added to * typeBuilder as getter method * @return boolean value *
    *
  • true - if node, typeBuilder, * nodeName equal null or node is added by uses
  • *
  • false - other cases
  • *
*/ private def boolean resolveLeafListSchemaNode(GeneratedTypeBuilder typeBuilder, LeafListSchemaNode node) { if ((node !== null) && (typeBuilder !== null)) { val nodeName = node.QName; var String nodeDesc = node.description; if (nodeDesc === null) { nodeDesc = ""; } if (nodeName !== null && !node.isAddedByUses()) { val TypeDefinition typeDef = node.type; val parentModule = findParentModule(schemaContext, node); var Type returnType = null; if (typeDef instanceof EnumTypeDefinition) { returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node); val enumTypeDef = typeDef as EnumTypeDefinition; val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName, typeBuilder); returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name); (typeProvider as TypeProviderImpl).putReferencedType(node.path, returnType); } else if (typeDef instanceof UnionType) { val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule); if (genTOBuilder !== null) { returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule) } } else if (typeDef instanceof BitsTypeDefinition) { val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule); returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name); } else { val Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef); returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions); } val listType = Types.listTypeFor(returnType); constructGetter(typeBuilder, nodeName.localName, nodeDesc, listType); return true; } } return false; } private def Type createReturnTypeForUnion(GeneratedTOBuilder genTOBuilder, TypeDefinition typeDef, GeneratedTypeBuilder typeBuilder, Module parentModule) { val Type returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name); genTOBuilder.setTypedef(true); genTOBuilder.setIsUnion(true); (typeProvider as TypeProviderImpl).addUnitsToGenTO(genTOBuilder, typeDef.getUnits()); // union builder val GeneratedTOBuilder unionBuilder = new GeneratedTOBuilderImpl(typeBuilder.getPackageName(), genTOBuilder.getName() + "Builder"); unionBuilder.setIsUnionBuilder(true); val MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance"); method.setReturnType(returnType); method.addParameter(Types.STRING, "defaultValue"); method.setAccessModifier(AccessModifier.PUBLIC); method.setStatic(true); val Set types = (typeProvider as TypeProviderImpl).additionalTypes.get(parentModule); if (types == null) { (typeProvider as TypeProviderImpl).additionalTypes.put(parentModule, Sets.newHashSet(unionBuilder.toInstance)) } else { types.add(unionBuilder.toInstance) } return returnType } private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode) { return addDefaultInterfaceDefinition(packageName, schemaNode, null); } /** * Instantiates generated type builder with packageName and * schemaNode. * * The new builder always implements * {@link org.opendaylight.yangtools.yang.binding.DataObject DataObject}.
* If schemaNode is instance of GroupingDefinition it also * implements {@link org.opendaylight.yangtools.yang.binding.Augmentable * Augmentable}.
* If schemaNode is instance of * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer * DataNodeContainer} it can also implement nodes which are specified in * uses. * * @param packageName * string with the name of the package to which * schemaNode belongs. * @param schemaNode * schema node for which is created generated type builder * @param parent parent type (can be null) * @return generated type builder schemaNode */ private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode, Type parent) { val it = addRawInterfaceDefinition(packageName, schemaNode, ""); qnameConstant(BindingMapping.QNAME_STATIC_FIELD_NAME,schemaNode.QName); if (parent === null) { addImplementsType(DATA_OBJECT); } else { addImplementsType(BindingTypes.childOf(parent)); } if (!(schemaNode instanceof GroupingDefinition)) { addImplementsType(augmentable(it)); } if (schemaNode instanceof DataNodeContainer) { addImplementedInterfaceFromUses(schemaNode as DataNodeContainer, it); } return it; } /** * Wraps the calling of the same overloaded method. * * @param packageName * string with the package name to which returning generated type * builder belongs * @param schemaNode * schema node which provide data about the schema node name * @return generated type builder for schemaNode */ private def GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode) { return addRawInterfaceDefinition(packageName, schemaNode, ""); } /** * Returns reference to generated type builder for specified * schemaNode with packageName. * * Firstly the generated type builder is searched in * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't * found it is created and added to genTypeBuilders. * * @param packageName * string with the package name to which returning generated type * builder belongs * @param schemaNode * schema node which provide data about the schema node name * @param prefix return type name prefix * @return generated type builder for schemaNode * @throws IllegalArgumentException *
    *
  • if schemaNode equals null
  • *
  • if packageName equals null
  • *
  • if Q name of schema node is null
  • *
  • if schema node name is null
  • *
* */ private def GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode, String prefix) { checkArgument(schemaNode !== null, "Data Schema Node cannot be NULL."); checkArgument(packageName !== null, "Package Name for Generated Type cannot be NULL."); checkArgument(schemaNode.QName !== null, "QName for Data Schema Node cannot be NULL."); val schemaNodeName = schemaNode.QName.localName; checkArgument(schemaNodeName !== null, "Local Name of QName for Data Schema Node cannot be NULL."); var String genTypeName; if (prefix === null) { genTypeName = BindingMapping.getClassName(schemaNodeName); } else { genTypeName = prefix + BindingMapping.getClassName(schemaNodeName); } //FIXME: Validation of name conflict val newType = new GeneratedTypeBuilderImpl(packageName, genTypeName); if (!genTypeBuilders.containsKey(packageName)) { val Map builders = new HashMap(); builders.put(genTypeName, newType); genTypeBuilders.put(packageName, builders); } else { val Map builders = genTypeBuilders.get(packageName); if (!builders.containsKey(genTypeName)) { builders.put(genTypeName, newType); } } return newType; } /** * Creates the name of the getter method from methodName. * * @param methodName * string with the name of the getter method * @param returnType return type * @return string with the name of the getter method for * methodName in JAVA method format */ public static def String getterMethodName(String localName, Type returnType) { val method = new StringBuilder(); if (BOOLEAN.equals(returnType)) { method.append("is"); } else { method.append("get"); } method.append(BindingMapping.getPropertyName(localName).toFirstUpper); return method.toString(); } /** * Created a method signature builder as part of * interfaceBuilder. * * The method signature builder is created for the getter method of * schemaNodeName. Also comment and * returnType information are added to the builder. * * @param interfaceBuilder * generated type builder for which the getter method should be * created * @param schemaNodeName * string with schema node name. The name will be the part of the * getter method name. * @param comment * string with comment for the getter method * @param returnType * type which represents the return type of the getter method * @return method signature builder which represents the getter method of * interfaceBuilder */ private def MethodSignatureBuilder constructGetter(GeneratedTypeBuilder interfaceBuilder, String schemaNodeName, String comment, Type returnType) { val getMethod = interfaceBuilder.addMethod(getterMethodName(schemaNodeName, returnType)); getMethod.setComment(comment); getMethod.setReturnType(returnType); return getMethod; } /** * Adds schemaNode to typeBuilder as getter method * or to genTOBuilder as property. * * @param basePackageName * string contains the module package name * @param schemaNode * data schema node which should be added as getter method to * typeBuilder or as a property to * genTOBuilder if is part of the list key * @param typeBuilder * generated type builder for the list schema node * @param genTOBuilder * generated TO builder for the list keys * @param listKeys * list of string which contains names of the list keys * @param module current module * @throws IllegalArgumentException *
    *
  • if schemaNode equals null
  • *
  • if typeBuilder equals null
  • *
*/ private def void addSchemaNodeToListBuilders(String basePackageName, DataSchemaNode schemaNode, GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder, List listKeys, Module module) { checkArgument(schemaNode !== null, "Data Schema Node cannot be NULL."); checkArgument(typeBuilder !== null, "Generated Type Builder cannot be NULL."); if (schemaNode instanceof LeafSchemaNode) { val leaf = schemaNode as LeafSchemaNode; val leafName = leaf.QName.localName; resolveLeafSchemaNodeAsMethod(typeBuilder, leaf); if (listKeys.contains(leafName)) { resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true); } } else if (!schemaNode.addedByUses) { if (schemaNode instanceof LeafListSchemaNode) { resolveLeafListSchemaNode(typeBuilder, schemaNode as LeafListSchemaNode); } else if (schemaNode instanceof ContainerSchemaNode) { containerToGenType(module, basePackageName, typeBuilder, typeBuilder, schemaNode as ContainerSchemaNode); } else if (schemaNode instanceof ChoiceNode) { choiceToGeneratedType(module, basePackageName, typeBuilder, schemaNode as ChoiceNode); } else if (schemaNode instanceof ListSchemaNode) { listToGenType(module, basePackageName, typeBuilder, typeBuilder, schemaNode as ListSchemaNode); } } } private def typeBuildersToGenTypes(Module module, GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder) { checkArgument(typeBuilder !== null, "Generated Type Builder cannot be NULL."); if (genTOBuilder !== null) { val genTO = genTOBuilder.toInstance(); constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO); genCtx.get(module).addGeneratedTOBuilder(genTOBuilder) } } /** * Selects the names of the list keys from list and returns * them as the list of the strings * * @param list * of string with names of the list keys * @return list of string which represents names of the list keys. If the * list contains no keys then the empty list is * returned. */ private def listKeys(ListSchemaNode list) { val List listKeys = new ArrayList(); if (list.keyDefinition !== null) { val keyDefinitions = list.keyDefinition; for (keyDefinition : keyDefinitions) { listKeys.add(keyDefinition.localName); } } return listKeys; } /** * Generates for the list which contains any list keys special * generated TO builder. * * @param packageName * string with package name to which the list belongs * @param list * list schema node which is source of data about the list name * @return generated TO builder which represents the keys of the * list or null if list is null or list of * key definitions is null or empty. */ private def GeneratedTOBuilder resolveListKeyTOBuilder(String packageName, ListSchemaNode list) { var GeneratedTOBuilder genTOBuilder = null; if ((list.keyDefinition !== null) && (!list.keyDefinition.isEmpty())) { val listName = list.QName.localName + "Key"; val String genTOName = BindingMapping.getClassName(listName); genTOBuilder = new GeneratedTOBuilderImpl(packageName, genTOName); } return genTOBuilder; } /** * Builds generated TO builders for typeDef of type * {@link org.opendaylight.yangtools.yang.model.util.UnionType UnionType} or * {@link org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition * BitsTypeDefinition} which are also added to typeBuilder as * enclosing transfer object. * * If more then one generated TO builder is created for enclosing then all * of the generated TO builders are added to typeBuilder as * enclosing transfer objects. * * @param typeDef * type definition which can be of type UnionType or * BitsTypeDefinition * @param typeBuilder * generated type builder to which is added generated TO created * from typeDef * @param leafName * string with name for generated TO builder * @param leaf * @param parentModule * @return generated TO builder for typeDef */ private def GeneratedTOBuilder addTOToTypeBuilder(TypeDefinition typeDef, GeneratedTypeBuilder typeBuilder, DataSchemaNode leaf, Module parentModule) { val classNameFromLeaf = BindingMapping.getClassName(leaf.QName); val List genTOBuilders = new ArrayList(); val packageName = typeBuilder.fullyQualifiedName; if (typeDef instanceof UnionTypeDefinition) { val List types = (typeProvider as TypeProviderImpl). provideGeneratedTOBuildersForUnionTypeDef(packageName, (typeDef as UnionTypeDefinition), classNameFromLeaf, leaf); genTOBuilders.addAll(types); var GeneratedTOBuilder resultTOBuilder = null; if (!types.isEmpty()) { resultTOBuilder = types.remove(0); for (GeneratedTOBuilder genTOBuilder : types) { resultTOBuilder.addEnclosingTransferObject(genTOBuilder); } } val GeneratedPropertyBuilder genPropBuilder = resultTOBuilder.addProperty("value"); genPropBuilder.setReturnType(Types.primitiveType("char[]", null)); resultTOBuilder.addEqualsIdentity(genPropBuilder); resultTOBuilder.addHashIdentity(genPropBuilder); resultTOBuilder.addToStringProperty(genPropBuilder); } else if (typeDef instanceof BitsTypeDefinition) { genTOBuilders.add( ((typeProvider as TypeProviderImpl) ). provideGeneratedTOBuilderForBitsTypeDefinition(packageName, typeDef, classNameFromLeaf)); } if (genTOBuilders !== null && !genTOBuilders.isEmpty()) { for (genTOBuilder : genTOBuilders) { typeBuilder.addEnclosingTransferObject(genTOBuilder); } return genTOBuilders.get(0); } return null; } /** * Adds the implemented types to type builder. * * The method passes through the list of uses in * {@code dataNodeContainer}. For every use is obtained corresponding * generated type from {@link BindingGeneratorImpl#allGroupings * allGroupings} which is added as implements type to * builder * * @param dataNodeContainer * element which contains the list of used YANG groupings * @param builder * builder to which are added implemented types according to * dataNodeContainer * @return generated type builder with all implemented types */ private def addImplementedInterfaceFromUses(DataNodeContainer dataNodeContainer, GeneratedTypeBuilder builder) { for (usesNode : dataNodeContainer.uses) { if (usesNode.groupingPath !== null) { val genType = findGroupingByPath(usesNode.groupingPath).toInstance if (genType === null) { throw new IllegalStateException( "Grouping " + usesNode.groupingPath + "is not resolved for " + builder.name); } builder.addImplementsType(genType); } } return builder; } private def GeneratedTypeBuilder findChildNodeByPath(SchemaPath path) { for (ctx : genCtx.values) { var result = ctx.getChildNode(path) if (result !== null) { return result } } return null } private def GeneratedTypeBuilder findGroupingByPath(SchemaPath path) { for (ctx : genCtx.values) { var result = ctx.getGrouping(path) if (result !== null) { return result } } return null } private def GeneratedTypeBuilder findCaseByPath(SchemaPath path) { for (ctx : genCtx.values) { var result = ctx.getCase(path) if (result !== null) { return result } } return null } private def Module getParentModule(SchemaNode node) { val QName qname = node.getPath().getPath().get(0); val URI namespace = qname.getNamespace(); val Date revision = qname.getRevision(); return schemaContext.findModuleByNamespaceAndRevision(namespace, revision); } public def getModuleContexts() { genCtx; } }