X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-generator-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fgenerator%2Fimpl%2FAbstractTypeGenerator.java;h=58e53a5022e9d5084088e3c6652c929542b8fa87;hb=42a49525a3b291a4af093090a54ab4c88a2313ca;hp=8cdce60969e008574330d59cc50496c9ed5db973;hpb=e6f7bf84fe00c345a988e592de5aa6c43b5b916b;p=mdsal.git diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java index 8cdce60969..58e53a5022 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java @@ -29,25 +29,34 @@ import static org.opendaylight.mdsal.binding.model.util.BindingTypes.childOf; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.choiceIn; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.identifiable; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.identifier; +import static org.opendaylight.mdsal.binding.model.util.BindingTypes.instanceNotification; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.keyedListAction; +import static org.opendaylight.mdsal.binding.model.util.BindingTypes.keyedListNotification; +import static org.opendaylight.mdsal.binding.model.util.BindingTypes.opaqueObject; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.rpcResult; import static org.opendaylight.mdsal.binding.model.util.Types.BOOLEAN; +import static org.opendaylight.mdsal.binding.model.util.Types.STRING; +import static org.opendaylight.mdsal.binding.model.util.Types.augmentationTypeFor; +import static org.opendaylight.mdsal.binding.model.util.Types.classType; import static org.opendaylight.mdsal.binding.model.util.Types.listTypeFor; import static org.opendaylight.mdsal.binding.model.util.Types.listenableFutureTypeFor; +import static org.opendaylight.mdsal.binding.model.util.Types.primitiveVoidType; import static org.opendaylight.mdsal.binding.model.util.Types.typeForClass; +import static org.opendaylight.mdsal.binding.model.util.Types.wildcardTypeFor; import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode; import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findNodeInSchemaContext; import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -74,7 +83,6 @@ import org.opendaylight.mdsal.binding.model.api.type.builder.TypeMemberBuilder; import org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil; import org.opendaylight.mdsal.binding.model.util.ReferencedTypeImpl; import org.opendaylight.mdsal.binding.model.util.TypeConstants; -import org.opendaylight.mdsal.binding.model.util.Types; import org.opendaylight.mdsal.binding.model.util.generated.type.builder.GeneratedPropertyBuilderImpl; import org.opendaylight.mdsal.binding.spec.naming.BindingMapping; import org.opendaylight.mdsal.binding.yang.types.AbstractTypeProvider; @@ -84,6 +92,8 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.model.api.ActionDefinition; import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer; +import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; @@ -92,6 +102,7 @@ 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.DocumentedNode; +import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus; import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; @@ -100,11 +111,11 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.ModuleImport; import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; +import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer; 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.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; import org.opendaylight.yangtools.yang.model.api.UsesNode; @@ -229,7 +240,7 @@ abstract class AbstractTypeGenerator { if (!module.getChildNodes().isEmpty()) { final GeneratedTypeBuilder moduleType = moduleToDataType(context); context.addModuleNode(moduleType); - resolveDataSchemaNodes(context, moduleType, moduleType, module.getChildNodes()); + resolveDataSchemaNodes(context, moduleType, moduleType, module.getChildNodes(), false); } return context; } @@ -267,12 +278,13 @@ abstract class AbstractTypeGenerator { } private GeneratedTypeBuilder processDataSchemaNode(final ModuleContext context, final Type baseInterface, - final DataSchemaNode node) { + final DataSchemaNode node, final boolean inGrouping) { if (node.isAugmenting() || node.isAddedByUses()) { return null; } final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(context, node, baseInterface); - annotateDeprecatedIfNecessary(node.getStatus(), genType); + defaultImplementedInterace(genType); + annotateDeprecatedIfNecessary(node, genType); final Module module = context.module(); genType.setModuleName(module.getName()); @@ -281,62 +293,68 @@ abstract class AbstractTypeGenerator { if (node instanceof DataNodeContainer) { context.addChildNodeType(node, genType); groupingsToGenTypes(context, ((DataNodeContainer) node).getGroupings()); - processUsesAugments((DataNodeContainer) node, context); + processUsesAugments((DataNodeContainer) node, context, inGrouping); } return genType; } private void containerToGenType(final ModuleContext context, final GeneratedTypeBuilder parent, - final Type baseInterface, final ContainerSchemaNode node) { - final GeneratedTypeBuilder genType = processDataSchemaNode(context, baseInterface, node); + final Type baseInterface, final ContainerSchemaNode node, final boolean inGrouping) { + final GeneratedTypeBuilder genType = processDataSchemaNode(context, baseInterface, node, inGrouping); if (genType != null) { constructGetter(parent, genType, node); - resolveDataSchemaNodes(context, genType, genType, node.getChildNodes()); - actionsToGenType(context, genType, node, null); + resolveDataSchemaNodes(context, genType, genType, node.getChildNodes(), inGrouping); + actionsToGenType(context, genType, node, null, inGrouping); + notificationsToGenType(context, genType, node, null, inGrouping); } } private void listToGenType(final ModuleContext context, final GeneratedTypeBuilder parent, - final Type baseInterface, final ListSchemaNode node) { - final GeneratedTypeBuilder genType = processDataSchemaNode(context, baseInterface, node); + final Type baseInterface, final ListSchemaNode node, final boolean inGrouping) { + final GeneratedTypeBuilder genType = processDataSchemaNode(context, baseInterface, node, inGrouping); if (genType != null) { + final List listKeys = listKeys(node); + final GeneratedTOBuilder keyTypeBuilder; + if (!listKeys.isEmpty()) { + keyTypeBuilder = typeProvider.newGeneratedTOBuilder(JavaTypeName.create( + packageNameForGeneratedType(context.modulePackageName(), node.getPath()), + BindingMapping.getClassName(node.getQName().getLocalName() + "Key"))) + .addImplementsType(identifier(genType)); + genType.addImplementsType(identifiable(keyTypeBuilder)); + } else { + keyTypeBuilder = null; + } + final ParameterizedType listType = listTypeFor(genType); constructGetter(parent, listType, node); constructNonnull(parent, listType, node); - final List listKeys = listKeys(node); - final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(context, node); - if (genTOBuilder != null) { - final Type identifierMarker = identifier(genType); - final Type identifiableMarker = identifiable(genTOBuilder); - genTOBuilder.addImplementsType(identifierMarker); - genType.addImplementsType(identifiableMarker); - - } - actionsToGenType(context, genType, node, genTOBuilder); + actionsToGenType(context, genType, node, keyTypeBuilder, inGrouping); + notificationsToGenType(context, genType, node, keyTypeBuilder, inGrouping); for (final DataSchemaNode schemaNode : node.getChildNodes()) { if (!schemaNode.isAugmenting()) { - addSchemaNodeToListBuilders(context, schemaNode, genType, genTOBuilder, listKeys); + addSchemaNodeToListBuilders(context, schemaNode, genType, keyTypeBuilder, listKeys, inGrouping); } } // serialVersionUID - if (genTOBuilder != null) { + if (keyTypeBuilder != null) { final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID"); - prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder))); - genTOBuilder.setSUID(prop); + prop.setValue(Long.toString(computeDefaultSUID(keyTypeBuilder))); + keyTypeBuilder.setSUID(prop); } - typeBuildersToGenTypes(context, genType, genTOBuilder); + typeBuildersToGenTypes(context, genType, keyTypeBuilder); } } - private void processUsesAugments(final DataNodeContainer node, final ModuleContext context) { + private void processUsesAugments(final DataNodeContainer node, final ModuleContext context, + final boolean inGrouping) { for (final UsesNode usesNode : node.getUses()) { for (final AugmentationSchemaNode augment : usesNode.getAugmentations()) { - usesAugmentationToGenTypes(context, augment, usesNode, node); - processUsesAugments(augment, context); + usesAugmentationToGenTypes(context, augment, usesNode, node, inGrouping); + processUsesAugments(augment, context, inGrouping); } } } @@ -413,8 +431,12 @@ abstract class AbstractTypeGenerator { } private void actionsToGenType(final ModuleContext context, - final Type parent, final T parentSchema, final Type keyType) { + final Type parent, final T parentSchema, final Type keyType, final boolean inGrouping) { for (final ActionDefinition action : parentSchema.getActions()) { + if (action.isAugmenting()) { + continue; + } + final GeneratedType input; final GeneratedType output; if (action.isAddedByUses()) { @@ -422,8 +444,8 @@ abstract class AbstractTypeGenerator { input = context.getChildNode(orig.getInput().getPath()).build(); output = context.getChildNode(orig.getOutput().getPath()).build(); } else { - input = actionContainer(context, RPC_INPUT, action.getInput()); - output = actionContainer(context, RPC_OUTPUT, action.getOutput()); + input = actionContainer(context, RPC_INPUT, action.getInput(), inGrouping); + output = actionContainer(context, RPC_OUTPUT, action.getOutput(), inGrouping); } if (!(parentSchema instanceof GroupingDefinition)) { @@ -437,7 +459,7 @@ abstract class AbstractTypeGenerator { qnameConstant(builder, JavaTypeName.create(context.modulePackageName(), BindingMapping.MODULE_INFO_CLASS_NAME), qname.getLocalName()); - annotateDeprecatedIfNecessary(action.getStatus(), builder); + annotateDeprecatedIfNecessary(action, builder); builder.addImplementsType(keyType != null ? keyedListAction(parent, keyType, input, output) : action(parent, input, output)); @@ -450,8 +472,7 @@ abstract class AbstractTypeGenerator { private Optional findOrigAction(final DataNodeContainer parent, final ActionDefinition action) { for (UsesNode uses : parent.getUses()) { final GroupingDefinition grp = findUsedGrouping(uses); - final Optional found = grp.getActions().stream() - .filter(act -> action.getQName().equals(act.getQName())).findFirst(); + final Optional found = grp.findAction(action.getQName()); if (found.isPresent()) { final ActionDefinition result = found.get(); return result.isAddedByUses() ? findOrigAction(grp, result) : found; @@ -462,9 +483,9 @@ abstract class AbstractTypeGenerator { } private GeneratedType actionContainer(final ModuleContext context, final Type baseInterface, - final ContainerSchemaNode schema) { - final GeneratedTypeBuilder genType = processDataSchemaNode(context, baseInterface, schema); - resolveDataSchemaNodes(context, genType, genType, schema.getChildNodes()); + final ContainerSchemaNode schema, final boolean inGrouping) { + final GeneratedTypeBuilder genType = processDataSchemaNode(context, baseInterface, schema, inGrouping); + resolveDataSchemaNodes(context, genType, genType, schema.getChildNodes(), inGrouping); return genType.build(); } @@ -501,12 +522,11 @@ abstract class AbstractTypeGenerator { for (final RpcDefinition rpc : rpcDefinitions) { if (rpc != null) { final String rpcName = BindingMapping.getClassName(rpc.getQName()); - final String rpcMethodName = BindingMapping.getPropertyName(rpcName); + final String rpcMethodName = BindingMapping.getRpcMethodName(rpc.getQName()); final MethodSignatureBuilder method = interfaceBuilder.addMethod(rpcMethodName); // Do not refer to annotation class, as it may not be available at runtime - // FIXME: migrate this to some other annotation type - method.addAnnotation("javax.annotation", "CheckReturnValue"); + method.addAnnotation("edu.umd.cs.findbugs.annotations", "CheckReturnValue"); addComment(method, rpc); method.addParameter( createRpcContainer(context, rpcName, rpc, verifyNotNull(rpc.getInput()), RPC_INPUT), "input"); @@ -520,15 +540,16 @@ abstract class AbstractTypeGenerator { private Type createRpcContainer(final ModuleContext context, final String rpcName, final RpcDefinition rpc, final ContainerSchemaNode schema, final Type type) { - processUsesAugments(schema, context); + processUsesAugments(schema, context, false); final GeneratedTypeBuilder outType = addRawInterfaceDefinition( JavaTypeName.create(context.modulePackageName(), rpcName + BindingMapping.getClassName(schema.getQName())), schema); addImplementedInterfaceFromUses(schema, outType); outType.addImplementsType(type); outType.addImplementsType(augmentable(outType)); - annotateDeprecatedIfNecessary(rpc.getStatus(), outType); - resolveDataSchemaNodes(context, outType, outType, schema.getChildNodes()); + defaultImplementedInterace(outType); + annotateDeprecatedIfNecessary(rpc, outType); + resolveDataSchemaNodes(context, outType, outType, schema.getChildNodes(), false); context.addChildNodeType(schema, outType); return outType.build(); } @@ -562,21 +583,22 @@ abstract class AbstractTypeGenerator { for (final NotificationDefinition notification : notifications) { if (notification != null) { - processUsesAugments(notification, context); + processUsesAugments(notification, context, false); final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition( context.modulePackageName(), notification, DATA_OBJECT, context); - annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface); + defaultImplementedInterace(notificationInterface); + annotateDeprecatedIfNecessary(notification, notificationInterface); notificationInterface.addImplementsType(NOTIFICATION); context.addChildNodeType(notification, notificationInterface); // Notification object resolveDataSchemaNodes(context, notificationInterface, notificationInterface, - notification.getChildNodes()); + notification.getChildNodes(), false); addComment(listenerInterface.addMethod("on" + notificationInterface.getName()) .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification") - .setReturnType(Types.primitiveVoidType()), notification); + .setReturnType(primitiveVoidType()), notification); } } @@ -584,6 +606,40 @@ abstract class AbstractTypeGenerator { context.addTopLevelNodeType(listenerInterface); } + private void notificationsToGenType( + final ModuleContext context, final Type parent, final T parentSchema, final Type keyType, + final boolean inGrouping) { + final Set notifications = parentSchema.getNotifications(); + if (notifications.isEmpty()) { + return; + } + + for (NotificationDefinition notif : notifications) { + if (notif.isAugmenting()) { + continue; + } + if (parentSchema instanceof GroupingDefinition) { + // Notifications cannot be really established, as they lack instantiation context, which would be + // completely described by an InstanceIdentifier -- hence we cannot create a binding class + continue; + } + + processUsesAugments(notif, context, false); + + final GeneratedTypeBuilder notifInterface = addDefaultInterfaceDefinition( + packageNameForGeneratedType(context.modulePackageName(), notif.getPath()), notif, DATA_OBJECT, context); + defaultImplementedInterace(notifInterface); + annotateDeprecatedIfNecessary(notif, notifInterface); + + notifInterface.addImplementsType(keyType != null ? keyedListNotification(notifInterface, parent, keyType) + : instanceNotification(notifInterface, parent)); + context.addChildNodeType(notif, notifInterface); + + // Notification object + resolveDataSchemaNodes(context, notifInterface, notifInterface, notif.getChildNodes(), false); + } + } + /** * Converts all identities of the module to the list of * Type objects. @@ -685,12 +741,14 @@ abstract class AbstractTypeGenerator { // Converts individual grouping to GeneratedType. Firstly generated type builder is created and every child // node of grouping is resolved to the method. final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(context, grouping); - annotateDeprecatedIfNecessary(grouping.getStatus(), genType); + narrowImplementedInterface(genType); + annotateDeprecatedIfNecessary(grouping, genType); context.addGroupingType(grouping, genType); - resolveDataSchemaNodes(context, genType, genType, grouping.getChildNodes()); + resolveDataSchemaNodes(context, genType, genType, grouping.getChildNodes(), true); groupingsToGenTypes(context, grouping.getGroupings()); - processUsesAugments(grouping, context); - actionsToGenType(context, genType, grouping, null); + processUsesAugments(grouping, context, true); + actionsToGenType(context, genType, grouping, null, true); + notificationsToGenType(context, genType, grouping, null, true); } } @@ -756,7 +814,7 @@ abstract class AbstractTypeGenerator { checkState(augSchema.getTargetPath() != null, "Augmentation Schema does not contain Target Path (Target Path is NULL)."); - processUsesAugments(augSchema, context); + processUsesAugments(augSchema, context, false); final SchemaPath targetPath = augSchema.getTargetPath(); SchemaNode targetSchemaNode = null; @@ -784,21 +842,21 @@ abstract class AbstractTypeGenerator { if (!(targetSchemaNode instanceof ChoiceSchemaNode)) { final Type targetType = new ReferencedTypeImpl(targetTypeBuilder.getIdentifier()); - addRawAugmentGenTypeDefinition(context, targetType, augSchema); + addRawAugmentGenTypeDefinition(context, targetType, augSchema, false); } else { generateTypesFromAugmentedChoiceCases(context, targetTypeBuilder.build(), - (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(), null); + (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(), null, false); } } private void usesAugmentationToGenTypes(final ModuleContext context, final AugmentationSchemaNode augSchema, - final UsesNode usesNode, final DataNodeContainer usesNodeParent) { + final UsesNode usesNode, final DataNodeContainer usesNodeParent, final boolean inGrouping) { checkArgument(augSchema != null, "Augmentation Schema cannot be NULL."); checkState(augSchema.getTargetPath() != null, "Augmentation Schema does not contain Target Path (Target Path is NULL)."); - processUsesAugments(augSchema, context); + processUsesAugments(augSchema, context, inGrouping); final SchemaPath targetPath = augSchema.getTargetPath(); final SchemaNode targetSchemaNode = findOriginalTargetFromGrouping(targetPath, usesNode); if (targetSchemaNode == null) { @@ -818,13 +876,13 @@ abstract class AbstractTypeGenerator { addRawAugmentGenTypeDefinition(context, packageNameForAugmentedGeneratedType(context.modulePackageName(), ((SchemaNode) usesNodeParent).getPath()), - targetTypeBuilder.build(), augSchema); + targetTypeBuilder.build(), augSchema, inGrouping); } else { - addRawAugmentGenTypeDefinition(context, targetTypeBuilder.build(), augSchema); + addRawAugmentGenTypeDefinition(context, targetTypeBuilder.build(), augSchema, inGrouping); } } else { generateTypesFromAugmentedChoiceCases(context, targetTypeBuilder.build(), - (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(), usesNodeParent); + (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(), usesNodeParent, inGrouping); } } @@ -897,7 +955,7 @@ abstract class AbstractTypeGenerator { */ private GeneratedTypeBuilder addRawAugmentGenTypeDefinition(final ModuleContext context, final String augmentPackageName, final Type targetTypeRef, - final AugmentationSchemaNode augSchema) { + final AugmentationSchemaNode augSchema, final boolean inGrouping) { Map augmentBuilders = genTypeBuilders.computeIfAbsent(augmentPackageName, k -> new HashMap<>()); final String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes()); @@ -913,24 +971,30 @@ abstract class AbstractTypeGenerator { JavaTypeName.create(augmentPackageName, augTypeName)); augTypeBuilder.addImplementsType(DATA_OBJECT); - augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef)); - annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder); + defaultImplementedInterace(augTypeBuilder); + + augTypeBuilder.addImplementsType(augmentationTypeFor(targetTypeRef)); + annotateDeprecatedIfNecessary(augSchema, augTypeBuilder); addImplementedInterfaceFromUses(augSchema, augTypeBuilder); - augSchemaNodeToMethods(context, augTypeBuilder, augSchema.getChildNodes()); + augSchemaNodeToMethods(context, augTypeBuilder, augSchema.getChildNodes(), inGrouping); + actionsToGenType(context, augTypeBuilder, augSchema, null, inGrouping); + notificationsToGenType(context, augTypeBuilder, augSchema, null, inGrouping); + augmentBuilders.put(augTypeName, augTypeBuilder); if (!augSchema.getChildNodes().isEmpty()) { context.addTypeToAugmentation(augTypeBuilder, augSchema); - } + context.addAugmentType(augTypeBuilder); return augTypeBuilder; } private GeneratedTypeBuilder addRawAugmentGenTypeDefinition(final ModuleContext context, final Type targetTypeRef, - final AugmentationSchemaNode augSchema) { - return addRawAugmentGenTypeDefinition(context, context.modulePackageName(), targetTypeRef, augSchema); + final AugmentationSchemaNode augSchema, final boolean inGrouping) { + return addRawAugmentGenTypeDefinition(context, context.modulePackageName(), targetTypeRef, augSchema, + inGrouping); } private static String getAugmentIdentifier(final List unknownSchemaNodes) { @@ -978,12 +1042,12 @@ abstract class AbstractTypeGenerator { * child nodes) could be added to it. */ private GeneratedTypeBuilder resolveDataSchemaNodes(final ModuleContext context, final GeneratedTypeBuilder parent, - final @Nullable Type childOf, final Iterable schemaNodes) { + final @Nullable Type childOf, final Iterable schemaNodes, final boolean inGrouping) { if (schemaNodes != null && parent != null) { final Type baseInterface = childOf == null ? DATA_OBJECT : childOf(childOf); for (final DataSchemaNode schemaNode : schemaNodes) { if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) { - addSchemaNodeToBuilderAsMethod(context, schemaNode, parent, baseInterface); + addSchemaNodeToBuilderAsMethod(context, schemaNode, parent, baseInterface, inGrouping); } } } @@ -1005,12 +1069,13 @@ abstract class AbstractTypeGenerator { * The getter method could be added to it. */ private GeneratedTypeBuilder augSchemaNodeToMethods(final ModuleContext context, - final GeneratedTypeBuilder typeBuilder, final Iterable schemaNodes) { + final GeneratedTypeBuilder typeBuilder, final Iterable schemaNodes, + final boolean inGrouping) { if (schemaNodes != null && typeBuilder != null) { final Type baseInterface = childOf(typeBuilder); for (final DataSchemaNode schemaNode : schemaNodes) { if (!schemaNode.isAugmenting()) { - addSchemaNodeToBuilderAsMethod(context, schemaNode, typeBuilder, baseInterface); + addSchemaNodeToBuilderAsMethod(context, schemaNode, typeBuilder, baseInterface, inGrouping); } } } @@ -1026,20 +1091,21 @@ abstract class AbstractTypeGenerator { * @param module current module */ private void addSchemaNodeToBuilderAsMethod(final ModuleContext context, final DataSchemaNode node, - final GeneratedTypeBuilder typeBuilder, final Type baseInterface) { + final GeneratedTypeBuilder typeBuilder, final Type baseInterface, final boolean inGrouping) { if (node != null && typeBuilder != null) { if (node instanceof LeafSchemaNode) { - resolveLeafSchemaNodeAsMethod(typeBuilder, (LeafSchemaNode) node, context); + resolveLeafSchemaNodeAsMethod(typeBuilder, (LeafSchemaNode) node, context, inGrouping); } else if (node instanceof LeafListSchemaNode) { - resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) node, context); + resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) node, context, inGrouping); } else if (node instanceof ContainerSchemaNode) { - containerToGenType(context, typeBuilder, baseInterface, (ContainerSchemaNode) node); + containerToGenType(context, typeBuilder, baseInterface, (ContainerSchemaNode) node, inGrouping); } else if (node instanceof ListSchemaNode) { - listToGenType(context, typeBuilder, baseInterface, (ListSchemaNode) node); + listToGenType(context, typeBuilder, baseInterface, (ListSchemaNode) node, inGrouping); } else if (node instanceof ChoiceSchemaNode) { - choiceToGeneratedType(context, typeBuilder, (ChoiceSchemaNode) node); + choiceToGeneratedType(context, typeBuilder, (ChoiceSchemaNode) node, inGrouping); + } else if (node instanceof AnyXmlSchemaNode || node instanceof AnyDataSchemaNode) { + opaqueToGeneratedType(context, typeBuilder, node); } else { - // TODO: anyxml not yet supported LOG.debug("Unable to add schema node {} as method in {}: unsupported type of node.", node.getClass(), typeBuilder.getFullyQualifiedName()); } @@ -1063,24 +1129,37 @@ abstract class AbstractTypeGenerator { * */ private void choiceToGeneratedType(final ModuleContext context, final GeneratedTypeBuilder parent, - final ChoiceSchemaNode choiceNode) { - checkArgument(choiceNode != null, "Choice Schema Node cannot be NULL."); - + final ChoiceSchemaNode choiceNode, final boolean inGrouping) { if (!choiceNode.isAddedByUses()) { final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition( JavaTypeName.create(packageNameForGeneratedType(context.modulePackageName(), choiceNode.getPath()), BindingMapping.getClassName(choiceNode.getQName())), choiceNode); choiceTypeBuilder.addImplementsType(choiceIn(parent)); - annotateDeprecatedIfNecessary(choiceNode.getStatus(), choiceTypeBuilder); + annotateDeprecatedIfNecessary(choiceNode, choiceTypeBuilder); context.addChildNodeType(choiceNode, choiceTypeBuilder); final GeneratedType choiceType = choiceTypeBuilder.build(); - generateTypesFromChoiceCases(context, choiceType, choiceNode); + generateTypesFromChoiceCases(context, choiceType, choiceNode, inGrouping); constructGetter(parent, choiceType, choiceNode); } } + private void opaqueToGeneratedType(final ModuleContext context, final GeneratedTypeBuilder parent, + final DataSchemaNode anyNode) { + if (!anyNode.isAddedByUses()) { + final GeneratedTypeBuilder anyxmlTypeBuilder = addRawInterfaceDefinition( + JavaTypeName.create(packageNameForGeneratedType(context.modulePackageName(), anyNode.getPath()), + BindingMapping.getClassName(anyNode.getQName())), anyNode); + anyxmlTypeBuilder.addImplementsType(opaqueObject(anyxmlTypeBuilder)).addImplementsType(childOf(parent)); + defaultImplementedInterace(anyxmlTypeBuilder); + annotateDeprecatedIfNecessary(anyNode, anyxmlTypeBuilder); + context.addChildNodeType(anyNode, anyxmlTypeBuilder); + + constructGetter(parent, anyxmlTypeBuilder.build(), anyNode); + } + } + /** * Converts caseNodes set to list of corresponding generated types. For every case which is not * added through augment or uses is created generated type builder. The package names for the builder is @@ -1097,7 +1176,7 @@ abstract class AbstractTypeGenerator { * */ private void generateTypesFromChoiceCases(final ModuleContext context, final Type refChoiceType, - final ChoiceSchemaNode choiceNode) { + final ChoiceSchemaNode choiceNode, final boolean inGrouping) { checkArgument(refChoiceType != null, "Referenced Choice Type cannot be NULL."); checkArgument(choiceNode != null, "ChoiceNode cannot be NULL."); @@ -1105,7 +1184,8 @@ abstract class AbstractTypeGenerator { if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) { final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(context, caseNode); caseTypeBuilder.addImplementsType(refChoiceType); - annotateDeprecatedIfNecessary(caseNode.getStatus(), caseTypeBuilder); + defaultImplementedInterace(caseTypeBuilder); + annotateDeprecatedIfNecessary(caseNode, caseTypeBuilder); context.addCaseType(caseNode.getPath(), caseTypeBuilder); context.addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode); final Iterable caseChildNodes = caseNode.getChildNodes(); @@ -1139,13 +1219,14 @@ abstract class AbstractTypeGenerator { if (childOfType == null) { childOfType = findGroupingByPath(parent.getPath()); } - resolveDataSchemaNodes(context, caseTypeBuilder, childOfType, caseChildNodes); + resolveDataSchemaNodes(context, caseTypeBuilder, childOfType, caseChildNodes, inGrouping); } else { - resolveDataSchemaNodes(context, caseTypeBuilder, moduleToDataType(context), caseChildNodes); + resolveDataSchemaNodes(context, caseTypeBuilder, moduleToDataType(context), caseChildNodes, + inGrouping); } } } - processUsesAugments(caseNode, context); + processUsesAugments(caseNode, context, inGrouping); } } @@ -1172,7 +1253,7 @@ abstract class AbstractTypeGenerator { @SuppressFBWarnings("NP_NULL_ON_SOME_PATH") private void generateTypesFromAugmentedChoiceCases(final ModuleContext context, final Type targetType, final ChoiceSchemaNode targetNode, final Iterable augmentedNodes, - final DataNodeContainer usesNodeParent) { + final DataNodeContainer usesNodeParent, final boolean inGrouping) { checkArgument(targetType != null, "Referenced Choice Type cannot be NULL."); checkArgument(augmentedNodes != null, "Set of Choice Case Nodes cannot be NULL."); @@ -1180,6 +1261,7 @@ abstract class AbstractTypeGenerator { if (caseNode != null) { final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(context, caseNode); caseTypeBuilder.addImplementsType(targetType); + defaultImplementedInterace(caseTypeBuilder); CaseSchemaNode node = null; final String caseLocalName = caseNode.getQName().getLocalName(); @@ -1199,7 +1281,8 @@ abstract class AbstractTypeGenerator { } final Iterable childNodes = node.getChildNodes(); if (childNodes != null) { - resolveDataSchemaNodes(context, caseTypeBuilder, findChildOfType(targetNode), childNodes); + resolveDataSchemaNodes(context, caseTypeBuilder, findChildOfType(targetNode), childNodes, + inGrouping); } context.addCaseType(caseNode.getPath(), caseTypeBuilder); context.addChoiceToCaseMapping(targetType, caseTypeBuilder, node); @@ -1274,7 +1357,7 @@ abstract class AbstractTypeGenerator { * */ private Type resolveLeafSchemaNodeAsMethod(final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf, - final ModuleContext context) { + final ModuleContext context, final boolean inGrouping) { if (leaf == null || typeBuilder == null || leaf.isAddedByUses()) { return null; } @@ -1282,10 +1365,10 @@ abstract class AbstractTypeGenerator { final Module parentModule = findParentModule(schemaContext, leaf); Type returnType = null; - final TypeDefinition typeDef = CompatUtils.compatLeafType(leaf); + final TypeDefinition typeDef = CompatUtils.compatType(leaf); if (isInnerType(leaf, typeDef)) { if (typeDef instanceof EnumTypeDefinition) { - returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf); + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, inGrouping); final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef; final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(), typeBuilder, context); @@ -1311,12 +1394,12 @@ abstract class AbstractTypeGenerator { // and apply restrictions from leaf type final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef); returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf, - restrictions); + restrictions, inGrouping); addPatternConstant(typeBuilder, leaf.getQName().getLocalName(), restrictions.getPatternConstraints()); } } else { final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef); - returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions); + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions, inGrouping); addPatternConstant(typeBuilder, leaf.getQName().getLocalName(), restrictions.getPatternConstraints()); } @@ -1401,7 +1484,7 @@ abstract class AbstractTypeGenerator { final boolean isReadOnly) { if (leaf != null && toBuilder != null) { Type returnType; - final TypeDefinition typeDef = CompatUtils.compatLeafType(leaf); + final TypeDefinition typeDef = CompatUtils.compatType(leaf); if (typeDef instanceof UnionTypeDefinition) { // GeneratedType for this type definition should have be already created final ModuleContext mc = moduleContext(typeDef.getQName().getModule()); @@ -1468,7 +1551,7 @@ abstract class AbstractTypeGenerator { * */ private boolean resolveLeafListSchemaNode(final GeneratedTypeBuilder typeBuilder, final LeafListSchemaNode node, - final ModuleContext context) { + final ModuleContext context, final boolean inGrouping) { if (node == null || typeBuilder == null || node.isAddedByUses()) { return false; } @@ -1481,7 +1564,7 @@ abstract class AbstractTypeGenerator { Type returnType = null; if (typeDef.getBaseType() == null) { if (typeDef instanceof EnumTypeDefinition) { - returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node); + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, inGrouping); final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef; final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName, typeBuilder, context); @@ -1496,12 +1579,12 @@ abstract class AbstractTypeGenerator { returnType = genTOBuilder.build(); } else { final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef); - returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions); + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions, inGrouping); addPatternConstant(typeBuilder, node.getQName().getLocalName(), restrictions.getPatternConstraints()); } } else { final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef); - returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions); + returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions, inGrouping); addPatternConstant(typeBuilder, node.getQName().getLocalName(), restrictions.getPatternConstraints()); } @@ -1537,17 +1620,12 @@ abstract class AbstractTypeGenerator { final MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance"); method.setReturnType(returnType); - method.addParameter(Types.STRING, "defaultValue"); + method.addParameter(STRING, "defaultValue"); method.setAccessModifier(AccessModifier.PUBLIC); method.setStatic(true); final GeneratedTransferObject unionBuilderType = unionBuilder.build(); - final Set types = typeProvider.getAdditionalTypes().get(parentModule); - if (types == null) { - typeProvider.getAdditionalTypes().put(parentModule, Sets.newHashSet(unionBuilderType)); - } else { - types.add(unionBuilderType); - } + typeProvider.getAdditionalTypes().computeIfAbsent(parentModule, key -> new HashSet<>()).add(unionBuilderType); } private GeneratedTypeBuilder addDefaultInterfaceDefinition(final ModuleContext context, @@ -1583,7 +1661,6 @@ abstract class AbstractTypeGenerator { } final GeneratedTypeBuilder it = addRawInterfaceDefinition(name, schemaNode); - it.addImplementsType(baseInterface); if (!(schemaNode instanceof GroupingDefinition)) { it.addImplementsType(augmentable(it)); @@ -1674,7 +1751,7 @@ abstract class AbstractTypeGenerator { getterMethodName(node.getQName().getLocalName(), returnType)); getMethod.setReturnType(returnType); - annotateDeprecatedIfNecessary(node.getStatus(), getMethod); + annotateDeprecatedIfNecessary(node, getMethod); addComment(getMethod, node); return getMethod; @@ -1685,7 +1762,7 @@ abstract class AbstractTypeGenerator { final MethodSignatureBuilder getMethod = interfaceBuilder.addMethod( BindingMapping.getNonnullMethodName(node.getQName().getLocalName())); getMethod.setReturnType(returnType).setDefault(true); - annotateDeprecatedIfNecessary(node.getStatus(), getMethod); + annotateDeprecatedIfNecessary(node, getMethod); } /** @@ -1707,14 +1784,14 @@ abstract class AbstractTypeGenerator { */ private void addSchemaNodeToListBuilders(final ModuleContext context, final DataSchemaNode schemaNode, final GeneratedTypeBuilder typeBuilder, final GeneratedTOBuilder genTOBuilder, - final List listKeys) { + final List listKeys, final boolean inGrouping) { 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 String leafName = leaf.getQName().getLocalName(); - Type type = resolveLeafSchemaNodeAsMethod(typeBuilder, leaf, context); + Type type = resolveLeafSchemaNodeAsMethod(typeBuilder, leaf, context, inGrouping); if (listKeys.contains(leafName)) { if (type == null) { resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true); @@ -1724,14 +1801,14 @@ abstract class AbstractTypeGenerator { } } else if (!schemaNode.isAddedByUses()) { if (schemaNode instanceof LeafListSchemaNode) { - resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) schemaNode, context); + resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) schemaNode, context, inGrouping); } else if (schemaNode instanceof ContainerSchemaNode) { containerToGenType(context, typeBuilder, childOf(typeBuilder), - (ContainerSchemaNode) schemaNode); + (ContainerSchemaNode) schemaNode, inGrouping); } else if (schemaNode instanceof ChoiceSchemaNode) { - choiceToGeneratedType(context, typeBuilder, (ChoiceSchemaNode) schemaNode); + choiceToGeneratedType(context, typeBuilder, (ChoiceSchemaNode) schemaNode, inGrouping); } else if (schemaNode instanceof ListSchemaNode) { - listToGenType(context, typeBuilder, childOf(typeBuilder), (ListSchemaNode) schemaNode); + listToGenType(context, typeBuilder, childOf(typeBuilder), (ListSchemaNode) schemaNode, inGrouping); } } } @@ -1757,32 +1834,19 @@ abstract class AbstractTypeGenerator { * an empty list is returned. */ private static List listKeys(final ListSchemaNode list) { - final List listKeys = new ArrayList<>(); - final List keyDefinition = list.getKeyDefinition(); - if (keyDefinition != null) { - for (final QName keyDef : keyDefinition) { - listKeys.add(keyDef.getLocalName()); - } - } - 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 GeneratedTOBuilder resolveListKeyTOBuilder(final ModuleContext context, final ListSchemaNode list) { - if (list.getKeyDefinition() != null && !list.getKeyDefinition().isEmpty()) { - return typeProvider.newGeneratedTOBuilder(JavaTypeName.create( - packageNameForGeneratedType(context.modulePackageName(), list.getPath()), - BindingMapping.getClassName(list.getQName().getLocalName() + "Key"))); + switch (keyDefinition.size()) { + case 0: + return Collections.emptyList(); + case 1: + return Collections.singletonList(keyDefinition.get(0).getLocalName()); + default: + final List listKeys = new ArrayList<>(keyDefinition.size()); + for (final QName keyDef : keyDefinition) { + listKeys.add(keyDef.getLocalName()); + } + return listKeys; } - return null; } /** @@ -1799,8 +1863,7 @@ abstract class AbstractTypeGenerator { private Type addTOToTypeBuilder(final UnionTypeDefinition typeDef, final GeneratedTypeBuilder typeBuilder, final DataSchemaNode leaf, final Module parentModule) { final List types = typeProvider.provideGeneratedTOBuildersForUnionTypeDef( - typeBuilder.getIdentifier().createEnclosed(BindingMapping.getClassName(leaf.getQName())), - typeDef, leaf); + allocateNestedType(typeBuilder.getIdentifier(), leaf.getQName()), typeDef, leaf); checkState(!types.isEmpty(), "No GeneratedTOBuilder objects generated from union %s", typeDef); final List genTOBuilders = new ArrayList<>(types); @@ -1833,11 +1896,9 @@ abstract class AbstractTypeGenerator { private GeneratedTOBuilder addTOToTypeBuilder(final BitsTypeDefinition typeDef, final GeneratedTypeBuilder typeBuilder, final DataSchemaNode leaf, final Module parentModule) { final GeneratedTOBuilder genTOBuilder = typeProvider.provideGeneratedTOBuilderForBitsTypeDefinition( - typeBuilder.getIdentifier().createEnclosed(BindingMapping.getClassName(leaf.getQName())), - typeDef, parentModule.getName()); + allocateNestedType(typeBuilder.getIdentifier(), leaf.getQName()), typeDef, parentModule.getName()); typeBuilder.addEnclosingTransferObject(genTOBuilder); return genTOBuilder; - } /** @@ -1853,13 +1914,13 @@ abstract class AbstractTypeGenerator { private GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer, final GeneratedTypeBuilder builder) { for (final UsesNode usesNode : dataNodeContainer.getUses()) { - final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath()).build(); + final GeneratedTypeBuilder genType = findGroupingByPath(usesNode.getGroupingPath()); if (genType == null) { throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for " + builder.getName()); } - builder.addImplementsType(genType); + builder.addImplementsType(genType.build()); } return builder; } @@ -1894,9 +1955,42 @@ abstract class AbstractTypeGenerator { return null; } - private static void annotateDeprecatedIfNecessary(final Status status, final AnnotableTypeBuilder builder) { - if (status == Status.DEPRECATED) { - builder.addAnnotation(DEPRECATED_ANNOTATION); + private static JavaTypeName allocateNestedType(final JavaTypeName parent, final QName child) { + // Single '$' suffix cannot come from user, this mirrors AbstractGeneratedTypeBuilder.addEnumeration() + return parent.createEnclosed(BindingMapping.getClassName(child), "$"); + } + + private static void annotateDeprecatedIfNecessary(final WithStatus node, final AnnotableTypeBuilder builder) { + switch (node.getStatus()) { + case DEPRECATED: + case OBSOLETE: + // FIXME: we really want to use a pre-made annotation + builder.addAnnotation(DEPRECATED_ANNOTATION); + break; + case CURRENT: + // No-op + break; + default: + throw new IllegalStateException("Unhandled status in " + node); } } + + private static void narrowImplementedInterface(final GeneratedTypeBuilder typeBuilder) { + defineImplementedInterfaceMethod(typeBuilder, wildcardTypeFor(typeBuilder.getIdentifier())); + } + + private static void defaultImplementedInterace(final GeneratedTypeBuilder typeBuilder) { + defineImplementedInterfaceMethod(typeBuilder, new ReferencedTypeImpl(typeBuilder.getIdentifier())) + .setDefault(true); + } + + private static MethodSignatureBuilder defineImplementedInterfaceMethod(final GeneratedTypeBuilder typeBuilder, + final Type classType) { + final MethodSignatureBuilder ret = typeBuilder + .addMethod(BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME) + .setAccessModifier(AccessModifier.PUBLIC) + .setReturnType(classType(classType)); + ret.addAnnotation(OVERRIDE_ANNOTATION); + return ret; + } }