X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=binding%2Fmdsal-binding-generator-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fgenerator%2Fimpl%2FAbstractTypeGenerator.java;h=8246669480c5806a86c653ccd2d40d1c4f1eb65a;hb=6cea51a1b795a222bb611b7a9501d1bc0308c3b8;hp=6d697783fc79a0ba46c32a012c13b96d2a327f78;hpb=22a74e14268b7fda9761b82946991e5f6b8a1f83;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 6d697783fc..8246669480 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 @@ -19,27 +19,30 @@ import static org.opendaylight.mdsal.binding.model.util.BindingTypes.DATA_OBJECT import static org.opendaylight.mdsal.binding.model.util.BindingTypes.DATA_ROOT; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.NOTIFICATION; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.NOTIFICATION_LISTENER; +import static org.opendaylight.mdsal.binding.model.util.BindingTypes.QNAME; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.ROUTING_CONTEXT; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.RPC_INPUT; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.RPC_OUTPUT; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.RPC_SERVICE; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.action; import static org.opendaylight.mdsal.binding.model.util.BindingTypes.augmentable; +import static org.opendaylight.mdsal.binding.model.util.BindingTypes.augmentation; 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.mapTypeFor; 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; @@ -51,6 +54,7 @@ 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; @@ -58,10 +62,12 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.mdsal.binding.generator.util.BaseYangTypes; import org.opendaylight.mdsal.binding.model.api.AccessModifier; import org.opendaylight.mdsal.binding.model.api.Constant; +import org.opendaylight.mdsal.binding.model.api.DefaultType; import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject; import org.opendaylight.mdsal.binding.model.api.GeneratedType; import org.opendaylight.mdsal.binding.model.api.JavaTypeName; @@ -78,19 +84,17 @@ import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilde import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder; 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.generated.type.builder.GeneratedPropertyBuilderImpl; import org.opendaylight.mdsal.binding.spec.naming.BindingMapping; import org.opendaylight.mdsal.binding.yang.types.AbstractTypeProvider; -import org.opendaylight.mdsal.binding.yang.types.BaseYangTypes; import org.opendaylight.mdsal.binding.yang.types.GroupingDefinitionDependencySort; 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.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; @@ -99,6 +103,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; @@ -107,19 +112,19 @@ 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; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; 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.PatternConstraint; import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; -import org.opendaylight.yangtools.yang.model.util.DataNodeIterator; import org.opendaylight.yangtools.yang.model.util.ModuleDependencySort; import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils; import org.opendaylight.yangtools.yang.model.util.type.CompatUtils; @@ -137,8 +142,8 @@ abstract class AbstractTypeGenerator { * Comparator based on augment target path. */ private static final Comparator AUGMENT_COMP = (o1, o2) -> { - final Iterator thisIt = o1.getTargetPath().getPathFromRoot().iterator(); - final Iterator otherIt = o2.getTargetPath().getPathFromRoot().iterator(); + final Iterator thisIt = o1.getTargetPath().getNodeIdentifiers().iterator(); + final Iterator otherIt = o2.getTargetPath().getNodeIdentifiers().iterator(); while (thisIt.hasNext()) { if (!otherIt.hasNext()) { @@ -181,7 +186,7 @@ abstract class AbstractTypeGenerator { /** * Holds reference to schema context to resolve data of augmented element when creating augmentation builder. */ - private final SchemaContext schemaContext; + private final @NonNull SchemaContext schemaContext; /** * Holds renamed elements. @@ -203,6 +208,10 @@ abstract class AbstractTypeGenerator { contexts.forEach(this::allAugmentsToGenTypes); } + final @NonNull SchemaContext schemaContext() { + return schemaContext; + } + final Collection moduleContexts() { return genCtx.values(); } @@ -220,7 +229,7 @@ abstract class AbstractTypeGenerator { abstract void addCodegenInformation(GeneratedTypeBuilderBase genType, Module module, SchemaNode node); abstract void addCodegenInformation(GeneratedTypeBuilder interfaceBuilder, Module module, String description, - Set nodes); + Collection nodes); abstract void addComment(TypeMemberBuilder genType, DocumentedNode node); @@ -258,11 +267,8 @@ abstract class AbstractTypeGenerator { private void allTypeDefinitionsToGenTypes(final ModuleContext context) { final Module module = context.module(); checkArgument(module.getName() != null, "Module name cannot be NULL."); - final DataNodeIterator it = new DataNodeIterator(module); - final List> typeDefinitions = it.allTypedefs(); - checkState(typeDefinitions != null, "Type Definitions for module %s cannot be NULL.", module.getName()); - for (final TypeDefinition typedef : typeDefinitions) { + for (final TypeDefinition typedef : SchemaNodeUtils.getAllTypeDefinitions(module)) { if (typedef != null) { final Type type = typeProvider.generatedTypeForExtendedDefinitionType(typedef, typedef); if (type != null) { @@ -280,7 +286,7 @@ abstract class AbstractTypeGenerator { } final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(context, node, baseInterface); defaultImplementedInterace(genType); - annotateDeprecatedIfNecessary(node.getStatus(), genType); + annotateDeprecatedIfNecessary(node, genType); final Module module = context.module(); genType.setModuleName(module.getName()); @@ -301,6 +307,7 @@ abstract class AbstractTypeGenerator { constructGetter(parent, genType, node); resolveDataSchemaNodes(context, genType, genType, node.getChildNodes(), inGrouping); actionsToGenType(context, genType, node, null, inGrouping); + notificationsToGenType(context, genType, node, null, inGrouping); } } @@ -308,35 +315,46 @@ abstract class AbstractTypeGenerator { final Type baseInterface, final ListSchemaNode node, final boolean inGrouping) { final GeneratedTypeBuilder genType = processDataSchemaNode(context, baseInterface, node, inGrouping); if (genType != 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); + 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; + } + // Decide whether to generate a List or a Map + final ParameterizedType listType; + if (keyTypeBuilder != null && !node.isUserOrdered()) { + listType = mapTypeFor(keyTypeBuilder, genType); + } else { + listType = listTypeFor(genType); } - actionsToGenType(context, genType, node, genTOBuilder, inGrouping); + + constructGetter(parent, listType, node); + constructNonnull(parent, listType, node); + + 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, inGrouping); + 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); } } @@ -394,8 +412,7 @@ abstract class AbstractTypeGenerator { checkArgument(module != null, "Module reference cannot be NULL."); checkState(module.getAugmentations() != null, "Augmentations Set cannot be NULL."); - final Set augmentations = module.getAugmentations(); - final List sortedAugmentations = new ArrayList<>(augmentations); + final List sortedAugmentations = new ArrayList<>(module.getAugmentations()); sortedAugmentations.sort(AUGMENT_COMP); return sortedAugmentations; @@ -450,7 +467,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)); @@ -462,7 +479,7 @@ abstract class AbstractTypeGenerator { private Optional findOrigAction(final DataNodeContainer parent, final ActionDefinition action) { for (UsesNode uses : parent.getUses()) { - final GroupingDefinition grp = findUsedGrouping(uses); + final GroupingDefinition grp = uses.getSourceGrouping(); final Optional found = grp.findAction(action.getQName()); if (found.isPresent()) { final ActionDefinition result = found.get(); @@ -499,7 +516,7 @@ abstract class AbstractTypeGenerator { private void rpcMethodsToGenType(final ModuleContext context) { final Module module = context.module(); checkArgument(module.getName() != null, "Module name cannot be NULL."); - final Set rpcDefinitions = module.getRpcs(); + final Collection rpcDefinitions = module.getRpcs(); checkState(rpcDefinitions != null, "Set of rpcs from module " + module.getName() + " cannot be NULL."); if (rpcDefinitions.isEmpty()) { return; @@ -513,7 +530,7 @@ 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 @@ -539,7 +556,7 @@ abstract class AbstractTypeGenerator { outType.addImplementsType(type); outType.addImplementsType(augmentable(outType)); defaultImplementedInterace(outType); - annotateDeprecatedIfNecessary(rpc.getStatus(), outType); + annotateDeprecatedIfNecessary(rpc, outType); resolveDataSchemaNodes(context, outType, outType, schema.getChildNodes(), false); context.addChildNodeType(schema, outType); return outType.build(); @@ -564,7 +581,7 @@ abstract class AbstractTypeGenerator { private void notificationsToGenType(final ModuleContext context) { final Module module = context.module(); checkArgument(module.getName() != null, "Module name cannot be NULL."); - final Set notifications = module.getNotifications(); + final Collection notifications = module.getNotifications(); if (notifications.isEmpty()) { return; } @@ -579,7 +596,7 @@ abstract class AbstractTypeGenerator { final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition( context.modulePackageName(), notification, DATA_OBJECT, context); defaultImplementedInterace(notificationInterface); - annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface); + annotateDeprecatedIfNecessary(notification, notificationInterface); notificationInterface.addImplementsType(NOTIFICATION); context.addChildNodeType(notification, notificationInterface); @@ -597,6 +614,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 Collection 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. @@ -610,7 +661,7 @@ abstract class AbstractTypeGenerator { * */ private void allIdentitiesToGenTypes(final ModuleContext context) { - final Set schemaIdentities = context.module().getIdentities(); + final Collection schemaIdentities = context.module().getIdentities(); if (schemaIdentities != null && !schemaIdentities.isEmpty()) { for (final IdentitySchemaNode identity : schemaIdentities) { @@ -646,7 +697,7 @@ abstract class AbstractTypeGenerator { } final GeneratedTypeBuilder newType = typeProvider.newGeneratedTypeBuilder(name); - final Set baseIdentities = identity.getBaseIdentities(); + final Collection baseIdentities = identity.getBaseIdentities(); if (!baseIdentities.isEmpty()) { for (IdentitySchemaNode baseIdentity : baseIdentities) { JavaTypeName base = renames.get(baseIdentity); @@ -676,7 +727,7 @@ abstract class AbstractTypeGenerator { private static Constant qnameConstant(final GeneratedTypeBuilderBase toBuilder, final JavaTypeName yangModuleInfo, final String localName) { - return toBuilder.addConstant(typeForClass(QName.class), BindingMapping.QNAME_STATIC_FIELD_NAME, + return toBuilder.addConstant(QNAME, BindingMapping.QNAME_STATIC_FIELD_NAME, new SimpleImmutableEntry<>(yangModuleInfo, localName)); } @@ -693,18 +744,20 @@ abstract class AbstractTypeGenerator { * collection of groupings from which types will be generated * */ - private void groupingsToGenTypes(final ModuleContext context, final Collection groupings) { + private void groupingsToGenTypes(final ModuleContext context, + final Collection groupings) { for (final GroupingDefinition grouping : new GroupingDefinitionDependencySort().sort(groupings)) { // 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); narrowImplementedInterface(genType); - annotateDeprecatedIfNecessary(grouping.getStatus(), genType); + annotateDeprecatedIfNecessary(grouping, genType); context.addGroupingType(grouping, genType); resolveDataSchemaNodes(context, genType, genType, grouping.getChildNodes(), true); groupingsToGenTypes(context, grouping.getGroupings()); processUsesAugments(grouping, context, true); actionsToGenType(context, genType, grouping, null, true); + notificationsToGenType(context, genType, grouping, null, true); } } @@ -771,10 +824,11 @@ abstract class AbstractTypeGenerator { "Augmentation Schema does not contain Target Path (Target Path is NULL)."); processUsesAugments(augSchema, context, false); - final SchemaPath targetPath = augSchema.getTargetPath(); + final SchemaNodeIdentifier targetPath = augSchema.getTargetPath(); SchemaNode targetSchemaNode = null; - targetSchemaNode = findDataSchemaNode(schemaContext, targetPath); + // FIXME: can we use findDataSchemaNode() instead? + targetSchemaNode = findDataSchemaNode(schemaContext, targetPath.getNodeIdentifiers()); if (targetSchemaNode instanceof DataSchemaNode && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) { if (targetSchemaNode instanceof DerivableSchemaNode) { targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orElse(null); @@ -797,8 +851,7 @@ abstract class AbstractTypeGenerator { } if (!(targetSchemaNode instanceof ChoiceSchemaNode)) { - final Type targetType = new ReferencedTypeImpl(targetTypeBuilder.getIdentifier()); - addRawAugmentGenTypeDefinition(context, targetType, augSchema, false); + addRawAugmentGenTypeDefinition(context, DefaultType.of(targetTypeBuilder), augSchema, false); } else { generateTypesFromAugmentedChoiceCases(context, targetTypeBuilder.build(), @@ -813,7 +866,7 @@ abstract class AbstractTypeGenerator { "Augmentation Schema does not contain Target Path (Target Path is NULL)."); processUsesAugments(augSchema, context, inGrouping); - final SchemaPath targetPath = augSchema.getTargetPath(); + final SchemaNodeIdentifier targetPath = augSchema.getTargetPath(); final SchemaNode targetSchemaNode = findOriginalTargetFromGrouping(targetPath, usesNode); if (targetSchemaNode == null) { throw new IllegalArgumentException("augment target not found: " + targetPath); @@ -842,16 +895,6 @@ abstract class AbstractTypeGenerator { } } - private GroupingDefinition findUsedGrouping(final UsesNode uses) { - final SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, uses.getGroupingPath() - .getPathFromRoot()); - if (targetGrouping instanceof GroupingDefinition) { - return (GroupingDefinition) targetGrouping; - } - - throw new IllegalArgumentException("Failed to resolve used grouping for " + uses); - } - /** * Convenient method to find node added by uses statement. * @@ -859,11 +902,12 @@ abstract class AbstractTypeGenerator { * @param parentUsesNode parent of uses node * @return node from its original location in grouping */ - private DataSchemaNode findOriginalTargetFromGrouping(final SchemaPath targetPath, final UsesNode parentUsesNode) { - SchemaNode result = findUsedGrouping(parentUsesNode); - for (final QName node : targetPath.getPathFromRoot()) { + private static DataSchemaNode findOriginalTargetFromGrouping(final SchemaNodeIdentifier targetPath, + final UsesNode parentUsesNode) { + SchemaNode result = parentUsesNode.getSourceGrouping(); + for (final QName node : targetPath.getNodeIdentifiers()) { if (result instanceof DataNodeContainer) { - final QName resultNode = node.withModule(result.getQName().getModule()); + final QName resultNode = node.bindTo(result.getQName().getModule()); result = ((DataNodeContainer) result).getDataChildByName(resultNode); } else if (result instanceof ChoiceSchemaNode) { result = findNamedCase((ChoiceSchemaNode) result, node.getLocalName()); @@ -929,12 +973,14 @@ abstract class AbstractTypeGenerator { augTypeBuilder.addImplementsType(DATA_OBJECT); defaultImplementedInterace(augTypeBuilder); - augTypeBuilder.addImplementsType(augmentationTypeFor(targetTypeRef)); - annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder); + augTypeBuilder.addImplementsType(augmentation(targetTypeRef)); + annotateDeprecatedIfNecessary(augSchema, augTypeBuilder); addImplementedInterfaceFromUses(augSchema, augTypeBuilder); 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()) { @@ -951,7 +997,7 @@ abstract class AbstractTypeGenerator { inGrouping); } - private static String getAugmentIdentifier(final List unknownSchemaNodes) { + private static String getAugmentIdentifier(final Collection unknownSchemaNodes) { for (final UnknownSchemaNode unknownSchemaNode : unknownSchemaNodes) { final QName nodeType = unknownSchemaNode.getNodeType(); if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.getLocalName()) @@ -996,7 +1042,8 @@ 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 boolean inGrouping) { + 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) { @@ -1023,7 +1070,7 @@ 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); @@ -1057,7 +1104,7 @@ abstract class AbstractTypeGenerator { listToGenType(context, typeBuilder, baseInterface, (ListSchemaNode) node, inGrouping); } else if (node instanceof ChoiceSchemaNode) { choiceToGeneratedType(context, typeBuilder, (ChoiceSchemaNode) node, inGrouping); - } else if (node instanceof AnyXmlSchemaNode || node instanceof AnyDataSchemaNode) { + } else if (node instanceof AnyxmlSchemaNode || node instanceof AnydataSchemaNode) { opaqueToGeneratedType(context, typeBuilder, node); } else { LOG.debug("Unable to add schema node {} as method in {}: unsupported type of node.", node.getClass(), @@ -1089,7 +1136,7 @@ abstract class AbstractTypeGenerator { 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(); @@ -1107,7 +1154,7 @@ abstract class AbstractTypeGenerator { BindingMapping.getClassName(anyNode.getQName())), anyNode); anyxmlTypeBuilder.addImplementsType(opaqueObject(anyxmlTypeBuilder)).addImplementsType(childOf(parent)); defaultImplementedInterace(anyxmlTypeBuilder); - annotateDeprecatedIfNecessary(anyNode.getStatus(), anyxmlTypeBuilder); + annotateDeprecatedIfNecessary(anyNode, anyxmlTypeBuilder); context.addChildNodeType(anyNode, anyxmlTypeBuilder); constructGetter(parent, anyxmlTypeBuilder.build(), anyNode); @@ -1134,15 +1181,15 @@ abstract class AbstractTypeGenerator { checkArgument(refChoiceType != null, "Referenced Choice Type cannot be NULL."); checkArgument(choiceNode != null, "ChoiceNode cannot be NULL."); - for (final CaseSchemaNode caseNode : choiceNode.getCases().values()) { + for (final CaseSchemaNode caseNode : choiceNode.getCases()) { if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) { final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(context, caseNode); caseTypeBuilder.addImplementsType(refChoiceType); defaultImplementedInterace(caseTypeBuilder); - annotateDeprecatedIfNecessary(caseNode.getStatus(), caseTypeBuilder); + annotateDeprecatedIfNecessary(caseNode, caseTypeBuilder); context.addCaseType(caseNode.getPath(), caseTypeBuilder); context.addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode); - final Iterable caseChildNodes = caseNode.getChildNodes(); + final Iterable caseChildNodes = caseNode.getChildNodes(); if (caseChildNodes != null) { final SchemaPath choiceNodeParentPath = choiceNode.getPath().getParent(); @@ -1151,8 +1198,10 @@ abstract class AbstractTypeGenerator { if (parent instanceof AugmentationSchemaNode) { final AugmentationSchemaNode augSchema = (AugmentationSchemaNode) parent; - final SchemaPath targetPath = augSchema.getTargetPath(); - SchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath); + final SchemaNodeIdentifier targetPath = augSchema.getTargetPath(); + // FIXME: can we use findDataSchemaNode? + SchemaNode targetSchemaNode = findNodeInSchemaContext(schemaContext, + targetPath.getNodeIdentifiers()); if (targetSchemaNode instanceof DataSchemaNode && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) { if (targetSchemaNode instanceof DerivableSchemaNode) { @@ -1206,7 +1255,8 @@ abstract class AbstractTypeGenerator { // FIXME: nullness rules need to untangled in this method @SuppressFBWarnings("NP_NULL_ON_SOME_PATH") private void generateTypesFromAugmentedChoiceCases(final ModuleContext context, - final Type targetType, final ChoiceSchemaNode targetNode, final Iterable augmentedNodes, + final Type targetType, final ChoiceSchemaNode targetNode, + final Iterable augmentedNodes, 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."); @@ -1233,7 +1283,7 @@ abstract class AbstractTypeGenerator { } else { node = findNamedCase(targetNode, caseLocalName); } - final Iterable childNodes = node.getChildNodes(); + final Iterable childNodes = node.getChildNodes(); if (childNodes != null) { resolveDataSchemaNodes(context, caseTypeBuilder, findChildOfType(targetNode), childNodes, inGrouping); @@ -1269,7 +1319,7 @@ abstract class AbstractTypeGenerator { } private static CaseSchemaNode findNamedCase(final ChoiceSchemaNode choice, final String caseName) { - final List cases = choice.findCaseNodes(caseName); + final List cases = choice.findCaseNodes(caseName); return cases.isEmpty() ? null : cases.get(0); } @@ -1416,7 +1466,8 @@ abstract class AbstractTypeGenerator { } } - private static IdentitySchemaNode findIdentityByName(final Set identities, final String name) { + private static IdentitySchemaNode findIdentityByName(final Collection identities, + final String name) { for (final IdentitySchemaNode id : identities) { if (id.getQName().getLocalName().equals(name)) { return id; @@ -1425,7 +1476,7 @@ abstract class AbstractTypeGenerator { return null; } - private Module findModuleFromImports(final Set imports, final String prefix) { + private Module findModuleFromImports(final Collection imports, final String prefix) { for (final ModuleImport imp : imports) { if (imp.getPrefix().equals(prefix)) { return schemaContext.findModule(imp.getModuleName(), imp.getRevision()).orElse(null); @@ -1522,7 +1573,7 @@ abstract class AbstractTypeGenerator { final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef; final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName, typeBuilder, context); - returnType = new ReferencedTypeImpl(enumBuilder.getIdentifier()); + returnType = DefaultType.of(enumBuilder); typeProvider.putReferencedType(node.getPath(), returnType); } else if (typeDef instanceof UnionTypeDefinition) { final UnionTypeDefinition unionDef = (UnionTypeDefinition)typeDef; @@ -1705,7 +1756,7 @@ abstract class AbstractTypeGenerator { getterMethodName(node.getQName().getLocalName(), returnType)); getMethod.setReturnType(returnType); - annotateDeprecatedIfNecessary(node.getStatus(), getMethod); + annotateDeprecatedIfNecessary(node, getMethod); addComment(getMethod, node); return getMethod; @@ -1716,7 +1767,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); } /** @@ -1763,6 +1814,8 @@ abstract class AbstractTypeGenerator { choiceToGeneratedType(context, typeBuilder, (ChoiceSchemaNode) schemaNode, inGrouping); } else if (schemaNode instanceof ListSchemaNode) { listToGenType(context, typeBuilder, childOf(typeBuilder), (ListSchemaNode) schemaNode, inGrouping); + } else if (schemaNode instanceof AnyxmlSchemaNode || schemaNode instanceof AnydataSchemaNode) { + opaqueToGeneratedType(context, typeBuilder, schemaNode); } } } @@ -1788,32 +1841,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; } /** @@ -1881,10 +1921,10 @@ abstract class AbstractTypeGenerator { private GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer, final GeneratedTypeBuilder builder) { for (final UsesNode usesNode : dataNodeContainer.getUses()) { - final GeneratedTypeBuilder genType = findGroupingByPath(usesNode.getGroupingPath()); + final GeneratedTypeBuilder genType = findGrouping(usesNode.getSourceGrouping()); if (genType == null) { - throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for " - + builder.getName()); + throw new IllegalStateException("Grouping " + usesNode.getSourceGrouping().getQName() + + " is not resolved for " + builder.getName()); } builder.addImplementsType(genType.build()); @@ -1902,6 +1942,16 @@ abstract class AbstractTypeGenerator { return null; } + private GeneratedTypeBuilder findGrouping(final GroupingDefinition grouping) { + for (final ModuleContext ctx : genCtx.values()) { + final GeneratedTypeBuilder result = ctx.getGrouping(grouping.getPath()); + if (result != null) { + return result; + } + } + return null; + } + private GeneratedTypeBuilder findGroupingByPath(final SchemaPath path) { for (final ModuleContext ctx : genCtx.values()) { final GeneratedTypeBuilder result = ctx.getGrouping(path); @@ -1927,9 +1977,20 @@ abstract class AbstractTypeGenerator { return parent.createEnclosed(BindingMapping.getClassName(child), "$"); } - private static void annotateDeprecatedIfNecessary(final Status status, final AnnotableTypeBuilder builder) { - if (status == Status.DEPRECATED) { - builder.addAnnotation(DEPRECATED_ANNOTATION); + private static void annotateDeprecatedIfNecessary(final WithStatus node, final AnnotableTypeBuilder builder) { + switch (node.getStatus()) { + case DEPRECATED: + // FIXME: we really want to use a pre-made annotation + builder.addAnnotation(DEPRECATED_ANNOTATION); + break; + case OBSOLETE: + builder.addAnnotation(DEPRECATED_ANNOTATION).addParameter("forRemoval", "true"); + break; + case CURRENT: + // No-op + break; + default: + throw new IllegalStateException("Unhandled status in " + node); } } @@ -1938,8 +1999,7 @@ abstract class AbstractTypeGenerator { } private static void defaultImplementedInterace(final GeneratedTypeBuilder typeBuilder) { - defineImplementedInterfaceMethod(typeBuilder, new ReferencedTypeImpl(typeBuilder.getIdentifier())) - .setDefault(true); + defineImplementedInterfaceMethod(typeBuilder, DefaultType.of(typeBuilder)).setDefault(true); } private static MethodSignatureBuilder defineImplementedInterfaceMethod(final GeneratedTypeBuilder typeBuilder,