X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=binding2%2Fmdsal-binding2-generator-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fjavav2%2Fgenerator%2Fimpl%2FGenHelperUtil.java;h=297e53cb4329c48f782b0ccecc8688fc3edaf1cd;hb=0ff85fbecb43b1071181f6b9b0f2d3eda1bb4c23;hp=8cdec5dc73ca6fc1c094fa4a5c860ab847e62796;hpb=ab986c3d142cced3b69e4ea379e3f24c26524d1b;p=mdsal.git diff --git a/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/impl/GenHelperUtil.java b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/impl/GenHelperUtil.java index 8cdec5dc73..297e53cb43 100644 --- a/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/impl/GenHelperUtil.java +++ b/binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/impl/GenHelperUtil.java @@ -8,69 +8,98 @@ package org.opendaylight.mdsal.binding.javav2.generator.impl; +import static com.google.common.base.Preconditions.checkArgument; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.addTOToTypeBuilder; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.annotateDeprecatedIfNecessary; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.augGenTypeName; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.constructGetter; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createDescription; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createReturnTypeForUnion; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.getAugmentIdentifier; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.isInnerType; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.qNameConstant; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveInnerEnumFromTypeDefinition; +import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveListKeyTOBuilder; +import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.computeDefaultSUID; +import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.encodeAngleBrackets; +import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.packageNameForGeneratedType; +import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.NOTIFICATION; +import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.parameterizedTypeFor; +import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode; +import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule; + import com.google.common.annotations.Beta; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; -import com.google.common.base.Splitter; -import com.google.common.base.Strings; import com.google.common.collect.Iterables; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.regex.Pattern; -import org.opendaylight.mdsal.binding.javav2.generator.impl.txt.yangTemplateForModule; -import org.opendaylight.mdsal.binding.javav2.generator.impl.txt.yangTemplateForNode; -import org.opendaylight.mdsal.binding.javav2.generator.impl.util.YangTextTemplate; +import java.util.Set; +import java.util.stream.Collectors; +import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider; import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil; import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes; +import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier; +import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer; +import org.opendaylight.mdsal.binding.javav2.generator.util.ReferencedTypeImpl; import org.opendaylight.mdsal.binding.javav2.generator.util.Types; +import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl; +import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTOBuilderImpl; import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl; -import org.opendaylight.mdsal.binding.javav2.model.api.Constant; +import org.opendaylight.mdsal.binding.javav2.generator.yang.types.GroupingDefinitionDependencySort; +import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl; +import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier; +import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject; import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType; +import org.opendaylight.mdsal.binding.javav2.model.api.ParameterizedType; +import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions; import org.opendaylight.mdsal.binding.javav2.model.api.Type; +import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.EnumBuilder; +import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedPropertyBuilder; +import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder; import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder; -import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilderBase; +import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.MethodSignatureBuilder; +import org.opendaylight.mdsal.binding.javav2.spec.base.BaseIdentity; import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode; +import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType; import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentable; -import org.opendaylight.mdsal.binding2.util.BindingMapping; +import org.opendaylight.mdsal.binding.javav2.util.BindingMapping; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; 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.DerivableSchemaNode; 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.NotificationDefinition; -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.Status; -import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.UsesNode; +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.SchemaContextUtil; +import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils; /** - * Helper util class used for generation of types in binding spec v2. + * Helper util class used for generation of types in Binding spec v2. */ @Beta final class GenHelperUtil { - private static final Pattern UNICODE_CHAR_PATTERN = Pattern.compile("\\\\+u"); - private static final Splitter BSDOT_SPLITTER = Splitter.on("\\."); - private static final char NEW_LINE = '\n'; - - /** - * Constant with the concrete name of identifier. - */ - private static final String AUGMENT_IDENTIFIER_NAME = "augment-identifier"; - - /** - * Constant with the concrete name of namespace. - */ - private static final String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext"; - private GenHelperUtil() { throw new UnsupportedOperationException("Util class"); } @@ -80,15 +109,15 @@ final class GenHelperUtil { * * @param module * Module object from which builder will be created - * @param genCtx - * @param verboseClassComments + * @param genCtx generated context + * @param verboseClassComments verbosity switch * * @return GeneratedTypeBuilder which is internal * representation of the module * @throws IllegalArgumentException * if module is null */ - static GeneratedTypeBuilder moduleToDataType(final Module module, Map genCtx, final boolean verboseClassComments) { + static GeneratedTypeBuilder moduleToDataType(final Module module, final Map genCtx, final boolean verboseClassComments) { Preconditions.checkArgument(module != null, "Module reference cannot be NULL."); final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data", verboseClassComments); @@ -109,22 +138,23 @@ final class GenHelperUtil { * @param postfix * string which is added to the module class name representation * as suffix - * @param verboseClassComments + * @param verboseClassComments verbosity switch * @return instance of GeneratedTypeBuilder which represents * module. * @throws IllegalArgumentException * if module is null */ - static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean verboseClassComments) { + static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean + verboseClassComments) { Preconditions.checkArgument(module != null, "Module reference cannot be NULL."); final String packageName = BindingMapping.getRootPackageName(module); - final String moduleName = BindingMapping.getClassName(module.getName()) + postfix; + // underscore used as separator for distinction of module name parts + final String moduleName = new StringBuilder(module.getName()).append('_').append(postfix).toString(); final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName); moduleBuilder.setDescription(createDescription(module, verboseClassComments)); moduleBuilder.setReference(module.getReference()); moduleBuilder.setModuleName(moduleName); - return moduleBuilder; } @@ -142,26 +172,23 @@ final class GenHelperUtil { * @param builder * builder to which are added implemented types according to * dataNodeContainer - * @param genCtx + * @param genCtx generated context * @return generated type builder with all implemented types */ - private static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer, - final GeneratedTypeBuilder builder, Map genCtx) { + static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer, + final GeneratedTypeBuilder builder, final Map genCtx) { for (final UsesNode usesNode : dataNodeContainer.getUses()) { - if (usesNode.getGroupingPath() != null) { - final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath(), genCtx).toInstance(); - if (genType == null) { - throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for " - + builder.getName()); - } - - builder.addImplementsType(genType); + final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath(), genCtx).toInstance(); + if (genType == null) { + throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for " + + builder.getName()); } + builder.addImplementsType(genType); } return builder; } - static GeneratedTypeBuilder findGroupingByPath(final SchemaPath path, Map genCtx) { + static GeneratedTypeBuilder findGroupingByPath(final SchemaPath path, final Map genCtx) { for (final ModuleContext ctx : genCtx.values()) { final GeneratedTypeBuilder result = ctx.getGrouping(path); if (result != null) { @@ -171,37 +198,6 @@ final class GenHelperUtil { return null; } - private static String createDescription(final Module module, final boolean verboseClassComments) { - final StringBuilder sb = new StringBuilder(); - final String moduleDescription = BindingGeneratorUtil.encodeAngleBrackets(module.getDescription()); - final String formattedDescription = YangTextTemplate.formatToParagraph(moduleDescription, 0); - - if (!Strings.isNullOrEmpty(formattedDescription)) { - sb.append(formattedDescription); - sb.append(NEW_LINE); - } - - if (verboseClassComments) { - sb.append("

"); - sb.append("This class represents the following YANG schema fragment defined in module "); - sb.append(module.getName()); - sb.append(""); - sb.append(NEW_LINE); - sb.append("

");
-            sb.append(NEW_LINE);
-            sb.append(BindingGeneratorUtil.encodeAngleBrackets(yangTemplateForModule.render(module).body()));
-            sb.append("
"); - } - - return replaceAllIllegalChars(sb); - } - - @VisibleForTesting - public static String replaceAllIllegalChars(final StringBuilder stringBuilder){ - final String ret = UNICODE_CHAR_PATTERN.matcher(stringBuilder).replaceAll("\\\\\\\\u"); - return ret.isEmpty() ? "" : ret; - } - /** * Adds the methods to typeBuilder which represent subnodes of * node for which typeBuilder was created. @@ -228,34 +224,54 @@ final class GenHelperUtil { * added to it. */ static GeneratedTypeBuilder resolveDataSchemaNodes(final Module module, final String basePackageName, - final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final Iterable schemaNodes) { + final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, + final Iterable schemaNodes, final Map genCtx, + final SchemaContext schemaContext, final boolean verboseClassComments, + final Map> genTypeBuilders, + final TypeProvider typeProvider, final BindingNamespaceType namespaceType) { + if (schemaNodes != null && parent != null) { for (final DataSchemaNode schemaNode : schemaNodes) { - if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) { - //TODO: design decomposition and implement it - //addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module); + if (!schemaNode.isAugmenting()) { + addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module, genCtx, + schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType); } } } return parent; } + static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String basePackageName, final SchemaNode + schemaNode, final Module module, final Map genCtx, final SchemaContext schemaContext, + final boolean verboseClassComments, final Map> genTypeBuilders, + final TypeProvider typeProvider, final BindingNamespaceType namespaceType) { + return addDefaultInterfaceDefinition(basePackageName, schemaNode, null, module, genCtx, schemaContext, + verboseClassComments, genTypeBuilders, typeProvider , namespaceType); + } + static Map processUsesAugments(final SchemaContext schemaContext, final - DataNodeContainer node, final Module module, Map genCtx, Map> genTypeBuilders, final boolean verboseClassComments) { + DataNodeContainer node, final Module module, Map genCtx, + final Map> genTypeBuilders, + final boolean verboseClassComments, final TypeProvider typeProvider, + final BindingNamespaceType namespaceType) { final String basePackageName = BindingMapping.getRootPackageName(module); for (final UsesNode usesNode : node.getUses()) { - for (final AugmentationSchema augment : usesNode.getAugmentations()) { - genCtx = AugmentToGenType.usesAugmentationToGenTypes(schemaContext, basePackageName, augment, module, - usesNode, - node, genCtx, genTypeBuilders, verboseClassComments); - genCtx = processUsesAugments(schemaContext, augment, module, genCtx, genTypeBuilders, verboseClassComments); + Map> augmentationsGrouped = + usesNode.getAugmentations().stream().collect(Collectors.groupingBy(AugmentationSchema::getTargetPath)); + for (Map.Entry> schemaPathAugmentListEntry : augmentationsGrouped.entrySet()) { + genCtx = AugmentToGenType.usesAugmentationToGenTypes(schemaContext, basePackageName, + schemaPathAugmentListEntry.getValue(), module, + usesNode, node, genCtx, genTypeBuilders, verboseClassComments, typeProvider, namespaceType); + for (AugmentationSchema augSchema : schemaPathAugmentListEntry.getValue()) { + genCtx = processUsesAugments(schemaContext, augSchema, module, genCtx, genTypeBuilders, + verboseClassComments, typeProvider, namespaceType); + } } } return genCtx; } - static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, Map genCtx) { + static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, final Map genCtx) { for (final ModuleContext ctx : genCtx.values()) { final GeneratedTypeBuilder result = ctx.getChildNode(path); if (result != null) { @@ -265,7 +281,7 @@ final class GenHelperUtil { return null; } - static GeneratedTypeBuilder findCaseByPath(final SchemaPath path, Map genCtx) { + static GeneratedTypeBuilder findCaseByPath(final SchemaPath path, final Map genCtx) { for (final ModuleContext ctx : genCtx.values()) { final GeneratedTypeBuilder result = ctx.getCase(path); if (result != null) { @@ -275,59 +291,56 @@ final class GenHelperUtil { return null; } - /** - * 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 in genCtx - */ static Map addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName, - final String basePackageName, final Type targetTypeRef, final AugmentationSchema augSchema, - Map> genTypeBuilders, Map genCtx) { + final Type targetTypeRef, final List schemaPathAugmentListEntry, + final Map> genTypeBuilders, final Map genCtx, + final SchemaContext schemaContext, final boolean verboseClassComments, final TypeProvider typeProvider, + final BindingNamespaceType namespaceType) { + + //pick augmentation grouped by augmentation target, there is always at least one + final AugmentationSchema augSchema = schemaPathAugmentListEntry.get(0); + + Map augmentBuilders = genTypeBuilders.computeIfAbsent( + augmentPackageName, k -> new HashMap<>()); - Map augmentBuilders = genTypeBuilders.get(augmentPackageName); - if (augmentBuilders == null) { - augmentBuilders = new HashMap<>(); - genTypeBuilders.put(augmentPackageName, augmentBuilders); + //this requires valid semantics in YANG model + String augIdentifier = null; + for (AugmentationSchema aug : schemaPathAugmentListEntry) { + augIdentifier = getAugmentIdentifier(aug.getUnknownSchemaNodes()); + break; } - final String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes()); - String augTypeName; - if (augIdentifier != null) { - augTypeName = BindingMapping.getClassName(augIdentifier); - } else { - augTypeName = augGenTypeName(augmentBuilders, targetTypeRef.getName()); + boolean isTypeNormalized = false; + if (augIdentifier == null) { + augIdentifier = augGenTypeName(augmentBuilders, targetTypeRef.getName()); + isTypeNormalized = true; } - GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName); + GeneratedTypeBuilderImpl augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augIdentifier, + false, isTypeNormalized); augTypeBuilder.addImplementsType(BindingTypes.TREE_NODE); + augTypeBuilder.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, augTypeBuilder)); augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef)); + augTypeBuilder.setBasePackageName(BindingMapping.getRootPackageName(module)); + if (namespaceType.equals(BindingNamespaceType.Data)) { + augTypeBuilder.setWithBuilder(true); + } annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder); - augTypeBuilder = addImplementedInterfaceFromUses(augSchema, augTypeBuilder, genCtx); - augTypeBuilder = augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema - .getChildNodes()); - augmentBuilders.put(augTypeName, augTypeBuilder); + //produces getters for augTypeBuilder eventually + for (AugmentationSchema aug : schemaPathAugmentListEntry) { + //apply all uses + addImplementedInterfaceFromUses(aug, augTypeBuilder, genCtx); + augSchemaNodeToMethods(module, BindingMapping.getRootPackageName(module), augTypeBuilder, augTypeBuilder, aug.getChildNodes(), + genCtx, schemaContext, verboseClassComments, typeProvider, genTypeBuilders, namespaceType); + } + + augmentBuilders.put(augTypeBuilder.getName(), augTypeBuilder); if(!augSchema.getChildNodes().isEmpty()) { genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema); - + genCtx.get(module).addTargetToAugmentation(augTypeBuilder, augSchema.getTargetPath()); } genCtx.get(module).addAugmentType(augTypeBuilder); return genCtx; @@ -356,63 +369,21 @@ final class GenHelperUtil { * added to it. */ private static GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName, - final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, - final Iterable schemaNodes) { - if ((schemaNodes != null) && (typeBuilder != null)) { + final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Iterable schemaNodes, + final Map genCtx, final SchemaContext schemaContext, final boolean + verboseClassComments, final TypeProvider typeProvider, final Map> genTypeBuilders, final BindingNamespaceType namespaceType) { + if (schemaNodes != null && typeBuilder != null) { for (final DataSchemaNode schemaNode : schemaNodes) { if (!schemaNode.isAugmenting()) { - //TODO: design decomposition and implement it - //addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module); + addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module, genCtx, + schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType); } } } return typeBuilder; } - /** - * @param unknownSchemaNodes - * @return nodeParameter of UnknownSchemaNode - */ - private static String getAugmentIdentifier(final List unknownSchemaNodes) { - for (final UnknownSchemaNode unknownSchemaNode : unknownSchemaNodes) { - final QName nodeType = unknownSchemaNode.getNodeType(); - if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.getLocalName()) - && YANG_EXT_NAMESPACE.equals(nodeType.getNamespace().toString())) { - return unknownSchemaNode.getNodeParameter(); - } - } - 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 static String augGenTypeName(final Map builders, final String genTypeName) { - int index = 1; - if (builders != null) { - while (builders.containsKey(genTypeName + index)) { - index = index + 1; - } - } - return genTypeName + index; - } - - static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode - schemaNode, final Module module, Map genCtx, final SchemaContext schemaContext, - final boolean verboseClassComments, Map> genTypeBuilders) { - return addDefaultInterfaceDefinition(packageName, schemaNode, null, module, genCtx, schemaContext, - verboseClassComments, genTypeBuilders); - } - /** * Instantiates generated type builder with packageName and * schemaNode. @@ -427,39 +398,102 @@ final class GenHelperUtil { * 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 basePackageName + * string contains the module package name * @param schemaNode * schema node for which is created generated type builder * @param parent * parent type (can be null) - * @param schemaContext + * @param schemaContext schema context * @return generated type builder schemaNode */ - private static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode - schemaNode, final Type parent, final Module module, Map genCtx, - final SchemaContext schemaContext, final boolean verboseClassComments, Map> genTypeBuilders) { - GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, schemaContext, "", - verboseClassComments, genTypeBuilders); - if (parent == null) { - it.addImplementsType(BindingTypes.TREE_NODE); - } else { - it.addImplementsType(BindingTypes.treeChildNode(parent)); + private static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String basePackageName, final SchemaNode + schemaNode, final Type parent, final Module module, final Map genCtx, + final SchemaContext schemaContext, final boolean verboseClassComments, final Map> genTypeBuilders, final TypeProvider typeProvider, final BindingNamespaceType namespaceType) { + + String suffix = ""; + if (schemaNode instanceof GroupingDefinition) { + suffix = "grouping"; + } else if (namespaceType.equals(BindingNamespaceType.Grouping)) { + suffix = "data"; } - if (!(schemaNode instanceof GroupingDefinition)) { - it.addImplementsType(BindingTypes.augmentable(it)); + + GeneratedTypeBuilder it = addRawInterfaceDefinition(basePackageName, schemaNode, schemaContext, "", suffix, + verboseClassComments, genTypeBuilders, namespaceType); + if (namespaceType.equals(BindingNamespaceType.Data)) { + if (parent == null) { + it.addImplementsType(BindingTypes.TREE_NODE); + } else { + if (parent instanceof ListSchemaNode) { + it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor + (BindingTypes.IDENTIFIABLE_ITEM, parent))); + } else { + it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor + (BindingTypes.ITEM, parent))); + it.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, it)); + } + } + + if (!(schemaNode instanceof GroupingDefinition)) { + it.addImplementsType(BindingTypes.augmentable(it)); + } + + if (schemaNode instanceof DerivableSchemaNode + && ((DerivableSchemaNode) schemaNode).isAddedByUses()) { + //TODO: The schema path of child node is not unique for YANG 1.1 + final GeneratedTypeBuilder originalType = + findChildNodeByPath(((DerivableSchemaNode) schemaNode).getOriginal().get().getPath(), genCtx); + Preconditions.checkState(originalType != null, "Original type can not be null!"); + it.addImplementsType(originalType.toInstance()); + } + + } else { + it.addImplementsType(BindingTypes.TREE_NODE); } if (schemaNode instanceof DataNodeContainer) { - //TODO: design decomposition and implement it - //groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings()); + groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings(), genCtx, schemaContext, + verboseClassComments, genTypeBuilders, typeProvider); it = addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it, genCtx); } return it; } + static GeneratedTypeBuilder resolveNotification(final GeneratedTypeBuilder listenerInterface, String + parentName, final String basePackageName, final NotificationDefinition notification, final Module module, + final SchemaContext schemaContext, final boolean verboseClassComments, Map> + genTypeBuilders, TypeProvider typeProvider, Map genCtx) { + + processUsesAugments(schemaContext, notification, module, genCtx, genTypeBuilders, + verboseClassComments, typeProvider, BindingNamespaceType.Data); + + final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition + (basePackageName, notification, null, module, genCtx, schemaContext, + verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Data); + annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface); + notificationInterface.addImplementsType(NOTIFICATION); + genCtx.get(module).addChildNodeType(notification, notificationInterface); + + // Notification object + resolveDataSchemaNodes(module, basePackageName, notificationInterface, + notificationInterface, notification.getChildNodes(), genCtx, schemaContext, + verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Data); + + //in case of tied notification, incorporate parent's localName + final StringBuilder sb = new StringBuilder("on_"); + if (parentName != null) { + sb.append(parentName).append('_'); + } + sb.append(notificationInterface.getName()); + + listenerInterface.addMethod(JavaIdentifierNormalizer.normalizeSpecificIdentifier(sb.toString(), JavaIdentifier.METHOD)) + .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification") + .setComment(encodeAngleBrackets(notification.getDescription())).setReturnType(Types.VOID); + return listenerInterface; + } + /** * Returns reference to generated type builder for specified * schemaNode with packageName. @@ -468,12 +502,11 @@ final class GenHelperUtil { * {@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 basePackageName + * string contains the module package name * @param schemaNode * schema node which provide data about the schema node name - * @param schemaContext + * @param schemaContext schema context * @param prefix * return type name prefix * @return generated type builder for schemaNode @@ -486,124 +519,769 @@ final class GenHelperUtil { * * */ - private static GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode, - final SchemaContext schemaContext, final String prefix, final boolean verboseClassComments, - Map> genTypeBuilders) { + static GeneratedTypeBuilder addRawInterfaceDefinition(final String basePackageName, final SchemaNode schemaNode, + final SchemaContext schemaContext, final String prefix, final String suffix, + final boolean verboseClassComments, final Map> genTypeBuilders, + final BindingNamespaceType namespaceType) { + Preconditions.checkArgument(schemaNode != null, "Data Schema Node cannot be NULL."); - Preconditions.checkArgument(packageName != null, "Package Name for Generated Type cannot be NULL."); - Preconditions.checkArgument(schemaNode.getQName() != null, "QName for Data Schema Node cannot be NULL."); - final String schemaNodeName = schemaNode.getQName().getLocalName(); + Preconditions.checkArgument(basePackageName != null, "Base package Name for Generated Type cannot be NULL."); + String schemaNodeName = schemaNode.getQName().getLocalName(); Preconditions.checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL."); - String genTypeName; - if (prefix == null) { - genTypeName = BindingMapping.getClassName(schemaNodeName); - } else { - genTypeName = prefix + BindingMapping.getClassName(schemaNodeName); + if (prefix != null && !prefix.isEmpty()) { + // underscore used as separator for distinction of class name parts + schemaNodeName = new StringBuilder(prefix).append('_').append(schemaNodeName).toString(); } - final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, genTypeName); + if (suffix != null && !suffix.isEmpty()) { + // underscore used as separator for distinction of class name parts + schemaNodeName = new StringBuilder(schemaNodeName).append('_').append(suffix).toString(); + } + + final String packageName = packageNameForGeneratedType(basePackageName, schemaNode.getPath(), namespaceType); + final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, schemaNodeName); final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode); qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName()); newType.addComment(schemaNode.getDescription()); - newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName(), schemaContext, verboseClassComments)); + newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName(), schemaContext, + verboseClassComments, namespaceType)); newType.setReference(schemaNode.getReference()); newType.setSchemaPath((List) schemaNode.getPath().getPathFromRoot()); newType.setModuleName(module.getName()); + newType.setBasePackageName(BindingMapping.getRootPackageName(module)); + newType.setWithBuilder(AuxiliaryGenUtils.hasBuilderClass(schemaNode, namespaceType)); - //FIXME: update genTypeBuilders for callers if (!genTypeBuilders.containsKey(packageName)) { final Map builders = new HashMap<>(); - builders.put(genTypeName, newType); + builders.put(newType.getName(), newType); genTypeBuilders.put(packageName, builders); } else { final Map builders = genTypeBuilders.get(packageName); - if (!builders.containsKey(genTypeName)) { - builders.put(genTypeName, newType); + if (!builders.containsKey(newType.getName())) { + builders.put(newType.getName(), newType); } } return newType; } - private static Constant qNameConstant(final GeneratedTypeBuilderBase toBuilder, final String constantName, - final QName name) { - return toBuilder.addConstant(Types.typeForClass(QName.class), constantName, name); + private static void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode node, + final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Module module, + final Map genCtx, final SchemaContext schemaContext, final boolean verboseClassComments, + final Map> genTypeBuilders, final TypeProvider typeProvider, + final BindingNamespaceType namespaceType) { + + if (node != null && typeBuilder != null) { + if (node instanceof ContainerSchemaNode) { + containerToGenType(module, basePackageName, typeBuilder, childOf, (ContainerSchemaNode) node, + schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType); + } else if (node instanceof LeafListSchemaNode) { + resolveLeafListSchemaNode(schemaContext, typeBuilder, (LeafListSchemaNode) node, module, + typeProvider, genCtx); + } else if (node instanceof LeafSchemaNode) { + resolveLeafSchemaNodeAsMethod("", schemaContext, typeBuilder, genCtx, (LeafSchemaNode) node, module, + typeProvider); + } else if (node instanceof ListSchemaNode) { + listToGenType(module, basePackageName, typeBuilder, childOf, (ListSchemaNode) node, schemaContext, + verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType); + } else if (node instanceof ChoiceSchemaNode) { + choiceToGenType(module, schemaContext, verboseClassComments, basePackageName, childOf, + (ChoiceSchemaNode) node, genTypeBuilders, genCtx, typeProvider, namespaceType); + } else if (node instanceof AnyXmlSchemaNode || node instanceof AnyDataSchemaNode) { + resolveAnyNodeAsMethod(schemaContext, typeBuilder, genCtx, node, module, typeProvider); + } + } + } + + /** + * 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 choiceNode + * choice node which is mapped to generated type. Also child + * nodes - cases are mapped to generated types. + * @throws IllegalArgumentException + *
    + *
  • if basePackageName is null
  • + *
  • if choiceNode is null
  • + *
+ */ + private static void choiceToGenType(final Module module, final SchemaContext schemaContext, final boolean + verboseClasssComments, final String basePackageName, final GeneratedTypeBuilder parent, final + ChoiceSchemaNode choiceNode, final Map> genTypeBuilders, + final Map genCtx, final TypeProvider typeProvider, final BindingNamespaceType namespaceType) { + checkArgument(basePackageName != null, "Base Package Name cannot be NULL."); + checkArgument(choiceNode != null, "Choice Schema Node cannot be NULL."); + + if (!choiceNode.isAddedByUses()) { + final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(basePackageName, choiceNode, + schemaContext, "", "", verboseClasssComments, genTypeBuilders, namespaceType); + constructGetter(parent, choiceNode.getQName().getLocalName(), + choiceNode.getDescription(), choiceTypeBuilder, choiceNode.getStatus()); + choiceTypeBuilder.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, choiceTypeBuilder)); + annotateDeprecatedIfNecessary(choiceNode.getStatus(), choiceTypeBuilder); + genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder); + generateTypesFromChoiceCases(module, schemaContext, genCtx, basePackageName, choiceTypeBuilder.toInstance(), + choiceNode, verboseClasssComments, typeProvider, genTypeBuilders, namespaceType); + } + } + + private static void containerToGenType(final Module module, final String basePackageName, + final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node, + final SchemaContext schemaContext, final boolean verboseClassComments, final Map genCtx, + final Map> genTypeBuilders, final TypeProvider typeProvider, + final BindingNamespaceType namespaceType) { + + final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node, + schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType); + if (genType != null) { + StringBuilder getterName = new StringBuilder(node.getQName().getLocalName()); + if (!namespaceType.equals(BindingNamespaceType.Data)) { + getterName.append('_').append(BindingNamespaceType.Data); + } + final MethodSignatureBuilder getter = constructGetter(parent, getterName.toString(), node.getDescription(), genType, node.getStatus()); + if (!namespaceType.equals(BindingNamespaceType.Data)) { + getter.setAccessModifier(AccessModifier.DEFAULT); + } + resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes(), genCtx, + schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType); + } + } + + private static void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder + parent, final GeneratedTypeBuilder childOf, final ListSchemaNode node, final SchemaContext schemaContext, + final boolean verboseClassComments, final Map genCtx, + final Map> genTypeBuilders, final TypeProvider typeProvider, + final BindingNamespaceType namespaceType) { + + final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node, + schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType); + if (genType != null) { + final String nodeName = node.getQName().getLocalName(); + constructGetter(parent, nodeName, node.getDescription(), Types.listTypeFor(genType), node.getStatus()); + final List listKeys = node.getKeyDefinition(); + final String packageName = new StringBuilder(packageNameForGeneratedType(basePackageName, node.getPath(), + BindingNamespaceType.Key)).append('.').append(nodeName).toString(); + + final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node); + + for (final DataSchemaNode schemaNode : node.getChildNodes()) { + if (!schemaNode.isAugmenting()) { + addSchemaNodeToListBuilders(nodeName, basePackageName, schemaNode, genType, genTOBuilder, listKeys, + module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments, namespaceType); + } + } + + // serialVersionUID + if (genTOBuilder != null) { + final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID"); + prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder))); + genTOBuilder.setSUID(prop); + } + + typeBuildersToGenTypes(module, genType, genTOBuilder, genCtx); + } + } + + private static void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder, + final GeneratedTOBuilder genTOBuilder, final Map genCtx) { + checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL."); + if (genTOBuilder != null) { + final GeneratedTransferObject genTO = genTOBuilder.toInstance(); + constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO, Status.CURRENT); + genCtx.get(module).addGeneratedTOBuilder(genTOBuilder); + } } - private static String createDescription(final SchemaNode schemaNode, final String fullyQualifiedName, - final SchemaContext schemaContext, final boolean verboseClassComments) { - final StringBuilder sb = new StringBuilder(); - final String nodeDescription = BindingGeneratorUtil.encodeAngleBrackets(schemaNode.getDescription()); - final String formattedDescription = YangTextTemplate.formatToParagraph(nodeDescription, 0); + /** + * 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 + * @param module + * Module in which type was defined + * @return boolean value + *
    + *
  • false - if leaf or typeBuilder are + * null
  • + *
  • true - in other cases
  • + *
+ */ + private static Type resolveLeafSchemaNodeAsMethod(final String nodeName, final SchemaContext schemaContext, + final GeneratedTypeBuilder typeBuilder, final Map genCtx, final LeafSchemaNode leaf, + final Module module, final TypeProvider typeProvider) { + if (leaf == null || typeBuilder == null) { + return null; + } + + final String leafName = leaf.getQName().getLocalName(); + if (leafName == null) { + return null; + } + + final Module parentModule = findParentModule(schemaContext, leaf); + Type returnType = null; + + final TypeDefinition typeDef = leaf.getType(); + if (isInnerType(leaf, typeDef)) { + if (typeDef instanceof EnumTypeDefinition) { + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf); + final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef; + final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(), + genCtx, typeBuilder, module); + if (enumBuilder != null) { + returnType = enumBuilder.toInstance(typeBuilder); + } + ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType); + } else if (typeDef instanceof UnionTypeDefinition) { + final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule, + typeProvider, schemaContext); + if (genTOBuilder != null) { + //TODO: https://bugs.opendaylight.org/show_bug.cgi?id=2289 + returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule, typeProvider); + } + } else if (typeDef instanceof BitsTypeDefinition) { + final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule, + typeProvider, schemaContext); + if (genTOBuilder != null) { + returnType = genTOBuilder.toInstance(); + } + } else { + // It is constrained version of already declared type (inner declared type exists, + // onlyfor special cases (Enum, Union, Bits), which were already checked. + // In order to get proper class we need to look up closest derived type + // and apply restrictions from leaf type + final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef); + returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf, + restrictions); + } + } else { + final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef); + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions); + } - if (!Strings.isNullOrEmpty(formattedDescription)) { - sb.append(formattedDescription); - sb.append(NEW_LINE); + if (returnType == null) { + return null; } - if (verboseClassComments) { - final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode); - final StringBuilder linkToBuilderClass = new StringBuilder(); - final String[] namespace = Iterables.toArray(BSDOT_SPLITTER.split(fullyQualifiedName), String.class); - final String className = namespace[namespace.length - 1]; + if (typeDef instanceof EnumTypeDefinition) { + ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType); + } + + String leafDesc = leaf.getDescription(); + if (leafDesc == null) { + leafDesc = ""; + } - if (hasBuilderClass(schemaNode)) { - linkToBuilderClass.append(className); - linkToBuilderClass.append("Builder"); + final String leafGetterName; + if (!"".equals(nodeName)) { + StringBuilder sb = new StringBuilder(nodeName) + .append('_') + .append(leafName); + leafGetterName = sb.toString(); + } else { + leafGetterName = leafName; + } + + constructGetter(typeBuilder, leafGetterName, leafDesc, returnType, leaf.getStatus()); + return returnType; + } + + /** + * 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 + * @param module module + * @param typeProvider type provider instance + * @param genCtx actual generated context + * @return boolean value + *
    + *
  • true - if node, typeBuilder, + * nodeName equal null or node is added by uses
  • + *
  • false - other cases
  • + *
+ */ + private static boolean resolveLeafListSchemaNode(final SchemaContext schemaContext, final GeneratedTypeBuilder + typeBuilder, final LeafListSchemaNode node, final Module module, final TypeProvider typeProvider, + final Map genCtx) { + if (node == null || typeBuilder == null || node.isAddedByUses()) { + return false; + } + + final QName nodeName = node.getQName(); + + final TypeDefinition typeDef = node.getType(); + final Module parentModule = findParentModule(schemaContext, node); + + Type returnType = null; + if (typeDef.getBaseType() == null) { + if (typeDef instanceof EnumTypeDefinition) { + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node); + final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef; + final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName, + genCtx, typeBuilder, module); + returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName()); + ((TypeProviderImpl) typeProvider).putReferencedType(node.getPath(), returnType); + } else if (typeDef instanceof UnionTypeDefinition) { + final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule, + typeProvider, schemaContext); + if (genTOBuilder != null) { + returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule, typeProvider); + } + } else if (typeDef instanceof BitsTypeDefinition) { + final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule, + typeProvider, schemaContext); + returnType = genTOBuilder.toInstance(); + } else { + final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef); + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions); } + } else { + final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef); + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions); + } + + final ParameterizedType listType = Types.listTypeFor(returnType); + constructGetter(typeBuilder, nodeName.getLocalName(), node.getDescription(), listType, node.getStatus()); + return true; + } - sb.append("

"); - sb.append("This class represents the following YANG schema fragment defined in module "); - sb.append(module.getName()); - sb.append(""); - sb.append(NEW_LINE); - sb.append("

");
-            sb.append(NEW_LINE);
-            sb.append(BindingGeneratorUtil.encodeAngleBrackets(yangTemplateForNode.render(schemaNode).body()));
-            sb.append("
"); - sb.append(NEW_LINE); - sb.append("The schema path to identify an instance is"); - sb.append(NEW_LINE); - sb.append(""); - sb.append(YangTextTemplate.formatSchemaPath(module.getName(), schemaNode.getPath().getPathFromRoot())); - sb.append(""); - sb.append(NEW_LINE); - - if (hasBuilderClass(schemaNode)) { - sb.append(NEW_LINE); - sb.append("

To create instances of this class use " + "{@link " + linkToBuilderClass + "}."); - sb.append(NEW_LINE); - sb.append("@see "); - sb.append(linkToBuilderClass); - sb.append(NEW_LINE); - if (schemaNode instanceof ListSchemaNode) { - final List keyDef = ((ListSchemaNode)schemaNode).getKeyDefinition(); - if (keyDef != null && !keyDef.isEmpty()) { - sb.append("@see "); - sb.append(className); - sb.append("Key"); + /** + * 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 module + * current module + * @param schemaContext + * current schema context + * @param genCtx + * actual generated context + * @param basePackageName + * string with the module package name + * @param refChoiceType + * type which represents superior case + * @param choiceNode + * choice case node which is mapped to generated type + * @param verboseClassComments + * Javadoc verbosity switch + * @throws IllegalArgumentException + *

    + *
  • if basePackageName equals null
  • + *
  • if refChoiceType equals null
  • + *
  • if caseNodes equals null
  • + *
+ */ + private static void generateTypesFromChoiceCases(final Module module, final SchemaContext schemaContext, + final Map genCtx, final String basePackageName, final Type refChoiceType, + final ChoiceSchemaNode choiceNode, final boolean verboseClassComments, final TypeProvider typeProvider, + final Map> genTypeBuilders, final BindingNamespaceType namespaceType) { + 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."); + + final Set caseNodes = choiceNode.getCases(); + if (caseNodes == null) { + return; + } + + for (final ChoiceCaseNode caseNode : caseNodes) { + if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) { + final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(basePackageName, caseNode, + module, genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType); + caseTypeBuilder.addImplementsType(refChoiceType); + caseTypeBuilder.setParentTypeForBuilder(refChoiceType); + annotateDeprecatedIfNecessary(caseNode.getStatus(), caseTypeBuilder); + genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder); + genCtx.get(module).addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode); + final Iterable caseChildNodes = caseNode.getChildNodes(); + if (caseChildNodes != null) { + final SchemaPath choiceNodeParentPath = choiceNode.getPath().getParent(); + + if (!Iterables.isEmpty(choiceNodeParentPath.getPathFromRoot())) { + SchemaNode parent = findDataSchemaNode(schemaContext, choiceNodeParentPath); + + if (parent instanceof AugmentationSchema) { + final AugmentationSchema augSchema = (AugmentationSchema) parent; + final SchemaPath targetPath = augSchema.getTargetPath(); + SchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath); + if (targetSchemaNode instanceof DataSchemaNode + && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) { + if (targetSchemaNode instanceof DerivableSchemaNode) { + targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orNull(); + } + if (targetSchemaNode == null) { + throw new IllegalStateException( + "Failed to find target node from grouping for augmentation " + augSchema + + " in module " + module.getName()); + } + } + parent = targetSchemaNode; + } + + Preconditions.checkState(parent != null, "Could not find Choice node parent %s", + choiceNodeParentPath); + GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.getPath(), genCtx); + if (childOfType == null) { + childOfType = findGroupingByPath(parent.getPath(), genCtx); + } + resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes, + genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType); + } else { + resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, moduleToDataType(module, + genCtx, verboseClassComments), caseChildNodes, genCtx, schemaContext, + verboseClassComments, genTypeBuilders, typeProvider, namespaceType); } - sb.append(NEW_LINE); } } + processUsesAugments(schemaContext, caseNode, module, genCtx, genTypeBuilders, verboseClassComments, + typeProvider, namespaceType); + } + } + + private static Type resolveAnyNodeAsMethod(final SchemaContext schemaContext, final GeneratedTypeBuilder + typeBuilder, final Map genCtx, final DataSchemaNode node, final Module module, + final TypeProvider typeProvider) { + + final String anyName = node.getQName().getLocalName(); + if (anyName == null) { + return null; + } + + String anyDesc = node.getDescription(); + if (anyDesc == null) { + anyDesc = ""; } - return replaceAllIllegalChars(sb); + Type returnType = Types.DOCUMENT; + + constructGetter(typeBuilder, anyName, anyDesc, returnType, node.getStatus()); + return returnType; } - private static void annotateDeprecatedIfNecessary(final Status status, final GeneratedTypeBuilder builder) { - if (status == Status.DEPRECATED) { - builder.addAnnotation("", "Deprecated"); + /** + * Adds schemaNode to typeBuilder as getter method + * or to genTOBuilder as property. + * + * @param nodeName + * string contains the name of list + * @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 QNames of the list keys + * @param module + * current module + * @param typeProvider + * provider that defines contract for generated types + * @param schemaContext + * schema context + * @param genCtx + * map of generated entities in context of YANG modules + * @param genTypeBuilders + * map of generated type builders + * @param verboseClassComments + * generate verbose comments + * @throws IllegalArgumentException + *
    + *
  • if schemaNode equals null
  • + *
  • if typeBuilder equals null
  • + *
+ */ + private static void addSchemaNodeToListBuilders(final String nodeName, final String basePackageName, + final DataSchemaNode schemaNode, final GeneratedTypeBuilder typeBuilder, + final GeneratedTOBuilder genTOBuilder, final List listKeys, final Module module, + final TypeProvider typeProvider, final SchemaContext schemaContext, final Map genCtx, + final Map> genTypeBuilders, final boolean verboseClassComments, + final BindingNamespaceType namespaceType) { + checkArgument(schemaNode != null, "Data Schema Node cannot be NULL."); + checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL."); + + if (schemaNode instanceof LeafSchemaNode) { + final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode; + final QName leafQName = leaf.getQName(); + + final Type type = resolveLeafSchemaNodeAsMethod(nodeName, schemaContext, typeBuilder, genCtx, leaf, module, + typeProvider); + if (listKeys.contains(leafQName)) { + if (type == null) { + resolveLeafSchemaNodeAsProperty(schemaContext, typeProvider, genCtx, genTOBuilder, leaf, true, + module); + } else { + AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, type, true); + } + } + } else if (!schemaNode.isAddedByUses()) { + if (schemaNode instanceof LeafListSchemaNode) { + resolveLeafListSchemaNode(schemaContext, typeBuilder, (LeafListSchemaNode) schemaNode, module, + typeProvider, genCtx); + } else if (schemaNode instanceof ContainerSchemaNode) { + containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode, + schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType); + } else if (schemaNode instanceof ListSchemaNode) { + listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode, + schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType); + } else if (schemaNode instanceof ChoiceSchemaNode) { + choiceToGenType(module, schemaContext, verboseClassComments, basePackageName, typeBuilder, + (ChoiceSchemaNode) schemaNode, genTypeBuilders, genCtx, typeProvider, namespaceType); + } } } - private static boolean hasBuilderClass(final SchemaNode schemaNode) { - if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode || - schemaNode instanceof RpcDefinition || schemaNode instanceof NotificationDefinition) { - return true; + private static boolean resolveLeafSchemaNodeAsProperty(final SchemaContext schemaContext, final TypeProvider + typeProvider, final Map genCtx, final GeneratedTOBuilder + toBuilder, final LeafSchemaNode leaf, final boolean isReadOnly, final Module module) { + + if (leaf != null && toBuilder != null) { + Type returnType; + final TypeDefinition typeDef = leaf.getType(); + if (typeDef instanceof UnionTypeDefinition) { + // GeneratedType for this type definition should be already + // created + final QName qname = typeDef.getQName(); + final Module unionModule = schemaContext.findModuleByNamespaceAndRevision(qname.getNamespace(), + qname.getRevision()); + final ModuleContext mc = genCtx.get(unionModule); + returnType = mc.getTypedefs().get(typeDef.getPath()); + } else if (typeDef instanceof EnumTypeDefinition && typeDef.getBaseType() == null) { + // Annonymous enumeration (already generated, since it is inherited via uses). + LeafSchemaNode originalLeaf = (LeafSchemaNode) SchemaNodeUtils.getRootOriginalIfPossible(leaf); + QName qname = originalLeaf.getQName(); + final Module enumModule = schemaContext.findModuleByNamespaceAndRevision(qname.getNamespace(), + qname.getRevision()); + returnType = genCtx.get(enumModule).getInnerType(originalLeaf.getType().getPath()); + } else { + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf); + } + return AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(toBuilder, leaf, returnType, isReadOnly); } return false; } + private static TypeDefinition getBaseOrDeclaredType(final TypeDefinition typeDef) { + final TypeDefinition baseType = typeDef.getBaseType(); + return (baseType != null && baseType.getBaseType() != null) ? baseType : typeDef; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static GeneratedTypeBuilder processDataSchemaNode(final Module module, final String basePackageName, + final GeneratedTypeBuilder childOf, final DataSchemaNode node, final SchemaContext schemaContext, + final boolean verboseClassComments, Map genCtx, final Map> genTypeBuilders, final TypeProvider typeProvider, final BindingNamespaceType namespaceType) { + + if (node.isAugmenting()) { + return null; + } + + final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(basePackageName, node, childOf, module, + genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType); + genType.addComment(node.getDescription()); + annotateDeprecatedIfNecessary(node.getStatus(), genType); + genType.setDescription(createDescription(node, genType.getFullyQualifiedName(), schemaContext, + verboseClassComments, namespaceType)); + genType.setModuleName(module.getName()); + genType.setReference(node.getReference()); + genType.setSchemaPath((List) node.getPath().getPathFromRoot()); + genType.setParentTypeForBuilder(childOf); + if (node instanceof DataNodeContainer) { + genCtx.get(module).addChildNodeType(node, genType); + genCtx = groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings(), genCtx, schemaContext, + verboseClassComments, genTypeBuilders, typeProvider); + processUsesAugments(schemaContext, (DataNodeContainer) node, module, genCtx, genTypeBuilders, + verboseClassComments, typeProvider, namespaceType); + } + return genType; + } + + /** + * 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 ModuleContext#groupings allGroupings} + * + * @param module + * current module + * @param groupings + * collection of groupings from which types will be generated + * @param typeProvider + * provider that defines contract for generated types + * @param schemaContext + * schema context + * @param genCtx + * map of generated entities in context of YANG modules + * @param genTypeBuilders + * map of generated type builders + * @param verboseClassComments + * generate verbose comments + * + */ + static Map groupingsToGenTypes(final Module module, final Collection + groupings, Map genCtx, final SchemaContext schemaContext, final boolean + verboseClassComments, Map> genTypeBuilders, final TypeProvider typeProvider) { + final String basePackageName = BindingMapping.getRootPackageName(module); + final List groupingsSortedByDependencies = new GroupingDefinitionDependencySort() + .sort(groupings); + for (final GroupingDefinition grouping : groupingsSortedByDependencies) { + genCtx = groupingToGenType(basePackageName, grouping, module, genCtx, schemaContext, + verboseClassComments, genTypeBuilders, typeProvider); + } + return genCtx; + } + + /** + * 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 + * @param typeProvider + * provider that defines contract for generated types + * @param schemaContext + * schema context + * @param genCtx + * map of generated entities in context of YANG modules + * @param genTypeBuilders + * map of generated type builders + * @param verboseClassComments + * generate verbose comments + * + * @return GeneratedType which is generated from grouping (object of type + * GroupingDefinition) + */ + private static Map groupingToGenType(final String basePackageName, final GroupingDefinition grouping, final Module + module, Map genCtx, final SchemaContext schemaContext, final boolean + verboseClassComments, Map> genTypeBuilders, final TypeProvider typeProvider) { + final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(basePackageName, grouping, module, genCtx, + schemaContext, verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Grouping); + annotateDeprecatedIfNecessary(grouping.getStatus(), genType); + genCtx.get(module).addGroupingType(grouping, genType); + resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes(), genCtx, + schemaContext, verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Grouping); + genCtx = groupingsToGenTypes(module, grouping.getGroupings(), genCtx, schemaContext, verboseClassComments, + genTypeBuilders, typeProvider); + genCtx = processUsesAugments(schemaContext, grouping, module, genCtx, genTypeBuilders, verboseClassComments, + typeProvider, BindingNamespaceType.Grouping); + return genCtx; + } + + /** + * //TODO: add information about multiple base identities in YANG 1.1 + * 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.IdentitySchemaNode + * BaseIdentity} is added + * + * @param module + * current module + * @param basePackageName + * string contains the module package name + * @param identity + * IdentitySchemaNode which contains data about identity + * @param schemaContext + * SchemaContext which is used to get package and name + * information about base of identity + * @param genCtx generated context + * @return returns generated context + */ + static Map identityToGenType(final Module module, final String basePackageName, + final IdentitySchemaNode identity, final SchemaContext schemaContext, Map genCtx, + boolean verboseClassComments, final Map> genTypeBuilders, + final TypeProvider typeProvider, Map generatedIdentities) { + + //check first if identity has been resolved as base identity of some other one + GeneratedTOBuilderImpl newType = generatedIdentities.get(identity.getQName()); + + if (newType == null) { + final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, identity.getPath(), + BindingNamespaceType.Identity); + newType = new GeneratedTOBuilderImpl(packageName, identity.getQName().getLocalName(), true, false); + } + + final Set baseIdentities = identity.getBaseIdentities(); + if (baseIdentities.size() == 0) { + //no base - abstract + final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(BaseIdentity.class.getPackage().getName(), + BaseIdentity.class.getSimpleName()); + newType.setExtendsType(gto.toInstance()); + generatedIdentities.put(identity.getQName(), newType); + } else { + //one base - inheritance + final IdentitySchemaNode baseIdentity = baseIdentities.iterator().next(); + final Module baseIdentityParentModule = SchemaContextUtil.findParentModule(schemaContext, baseIdentity); + final String returnTypePkgName = new StringBuilder(BindingMapping.getRootPackageName + (baseIdentityParentModule)) + .append('.') + .append(BindingNamespaceType.Identity.getPackagePrefix()) + .toString(); + + final GeneratedTOBuilderImpl existingIdentityGto = generatedIdentities.get(baseIdentity.getQName()); + if (existingIdentityGto != null) { + newType.setExtendsType(existingIdentityGto.toInstance()); + } else { + final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(returnTypePkgName, + baseIdentity.getQName().getLocalName()); + newType.setExtendsType(gto.toInstance()); + generatedIdentities.put(baseIdentity.getQName(), gto); + } + + //FIXME: more bases - possible composition, multiple inheritance not possible + } + generatedIdentities.put(identity.getQName(), newType); + + newType.setAbstract(true); + newType.addComment(identity.getDescription()); + newType.setDescription(createDescription(identity, newType.getFullyQualifiedName(), schemaContext, + verboseClassComments, BindingNamespaceType.Identity)); + newType.setReference(identity.getReference()); + newType.setModuleName(module.getName()); + newType.setSchemaPath((List) identity.getPath().getPathFromRoot()); + + qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, identity.getQName()); + + genCtx.get(module).addIdentityType(identity.getQName(), newType); + return genCtx; + } }