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=1ba24c4a07b12c9f97d10abb44131300f95ca9a6;hb=8c4ab985c1723336640324789c65489e71deb4e0;hp=c5065cfc1a4d2c889530013219e3d757f037a794;hpb=30952238d240260310d357c2e80be55021ccb1fc;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 c5065cfc1a..1ba24c4a07 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,29 @@ 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.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 +53,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; @@ -62,6 +65,7 @@ import java.util.Set; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.mdsal.binding.model.api.AccessModifier; import org.opendaylight.mdsal.binding.model.api.Constant; +import org.opendaylight.mdsal.binding.model.api.Enumeration; import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject; import org.opendaylight.mdsal.binding.model.api.GeneratedType; import org.opendaylight.mdsal.binding.model.api.JavaTypeName; @@ -89,8 +93,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.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,20 @@ 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.TypedDataSchemaNode; import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; 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.LeafrefTypeDefinition; 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; @@ -229,15 +235,17 @@ abstract class AbstractTypeGenerator { genCtx.put(module.getQNameModule(), context); allTypeDefinitionsToGenTypes(context); groupingsToGenTypes(context, module.getGroupings()); - rpcMethodsToGenType(context); allIdentitiesToGenTypes(context); - notificationsToGenType(context); if (!module.getChildNodes().isEmpty()) { final GeneratedTypeBuilder moduleType = moduleToDataType(context); context.addModuleNode(moduleType); resolveDataSchemaNodes(context, moduleType, moduleType, module.getChildNodes(), false); } + + // Resolve RPCs and notifications only after we have created instantiated tree + rpcMethodsToGenType(context); + notificationsToGenType(context); return context; } @@ -258,11 +266,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 +285,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 +306,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 +314,39 @@ abstract class AbstractTypeGenerator { 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, inGrouping); + 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); } } @@ -416,6 +426,11 @@ abstract class AbstractTypeGenerator { final Module module = context.module(); addImplementedInterfaceFromUses(module, moduleDataTypeBuilder); moduleDataTypeBuilder.addImplementsType(DATA_ROOT); + // if we have more than 2 top level uses statements we need to define getImplementedInterface() on the + // top level DataRoot object + if (module.getUses().size() > 1) { + narrowImplementedInterface(moduleDataTypeBuilder); + } addCodegenInformation(moduleDataTypeBuilder, module); return moduleDataTypeBuilder; @@ -424,12 +439,19 @@ abstract class AbstractTypeGenerator { private void actionsToGenType(final ModuleContext context, 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()) { final ActionDefinition orig = findOrigAction(parentSchema, action).get(); - input = context.getChildNode(orig.getInput().getPath()).build(); - output = context.getChildNode(orig.getOutput().getPath()).build(); + // Original definition may live in a different module, make sure we account for that + final ModuleContext origContext = moduleContext( + orig.getPath().getPathFromRoot().iterator().next().getModule()); + input = context.addAliasType(origContext, orig.getInput(), action.getInput()); + output = context.addAliasType(origContext, orig.getOutput(), action.getOutput()); } else { input = actionContainer(context, RPC_INPUT, action.getInput(), inGrouping); output = actionContainer(context, RPC_OUTPUT, action.getOutput(), inGrouping); @@ -443,10 +465,9 @@ abstract class AbstractTypeGenerator { final GeneratedTypeBuilder builder = typeProvider.newGeneratedTypeBuilder(JavaTypeName.create( packageNameForGeneratedType(context.modulePackageName(), action.getPath()), BindingMapping.getClassName(qname))); - qnameConstant(builder, JavaTypeName.create(context.modulePackageName(), - BindingMapping.MODULE_INFO_CLASS_NAME), qname.getLocalName()); + qnameConstant(builder, context.moduleInfoType(), qname.getLocalName()); - annotateDeprecatedIfNecessary(action.getStatus(), builder); + annotateDeprecatedIfNecessary(action, builder); builder.addImplementsType(keyType != null ? keyedListAction(parent, keyType, input, output) : action(parent, input, output)); @@ -457,10 +478,12 @@ abstract class AbstractTypeGenerator { } private Optional findOrigAction(final DataNodeContainer parent, final ActionDefinition action) { + final QName qname = action.getQName(); for (UsesNode uses : parent.getUses()) { final GroupingDefinition grp = findUsedGrouping(uses); - final Optional found = grp.getActions().stream() - .filter(act -> action.getQName().equals(act.getQName())).findFirst(); + // Target grouping may reside in a different module, hence we need to rebind the QName to match grouping's + // namespace + final Optional found = grp.findAction(qname.withModule(grp.getQName().getModule())); if (found.isPresent()) { final ActionDefinition result = found.get(); return result.isAddedByUses() ? findOrigAction(grp, result) : found; @@ -510,7 +533,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 @@ -529,14 +552,14 @@ abstract class AbstractTypeGenerator { private Type createRpcContainer(final ModuleContext context, final String rpcName, final RpcDefinition rpc, final ContainerSchemaNode schema, final Type type) { processUsesAugments(schema, context, false); - final GeneratedTypeBuilder outType = addRawInterfaceDefinition( + final GeneratedTypeBuilder outType = addRawInterfaceDefinition(context, JavaTypeName.create(context.modulePackageName(), rpcName + BindingMapping.getClassName(schema.getQName())), schema); addImplementedInterfaceFromUses(schema, outType); 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(); @@ -576,7 +599,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); @@ -594,6 +617,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. @@ -665,15 +722,14 @@ abstract class AbstractTypeGenerator { newType.setModuleName(module.getName()); newType.setSchemaPath(identity.getPath()); - qnameConstant(newType, JavaTypeName.create(context.modulePackageName(), BindingMapping.MODULE_INFO_CLASS_NAME), - identity.getQName().getLocalName()); + qnameConstant(newType, context.moduleInfoType(), identity.getQName().getLocalName()); context.addIdentityType(identity, newType); } 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)); } @@ -696,12 +752,13 @@ abstract class AbstractTypeGenerator { // 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); } } @@ -715,16 +772,15 @@ abstract class AbstractTypeGenerator { * @param module Module in which type should be generated * @return enumeration builder which contains data from enumTypeDef */ - private EnumBuilder resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final QName enumName, + private Enumeration resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final QName enumName, final GeneratedTypeBuilder typeBuilder, final ModuleContext context) { - if (enumTypeDef != null && typeBuilder != null && enumTypeDef.getQName().getLocalName() != null) { - final EnumBuilder enumBuilder = typeBuilder.addEnumeration(BindingMapping.getClassName(enumName)); - typeProvider.addEnumDescription(enumBuilder, enumTypeDef); - enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef); - context.addInnerTypedefType(enumTypeDef.getPath(), enumBuilder); - return enumBuilder; - } - return null; + final EnumBuilder enumBuilder = typeBuilder.addEnumeration(BindingMapping.getClassName(enumName)); + typeProvider.addEnumDescription(enumBuilder, enumTypeDef); + enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef); + final Enumeration ret = enumBuilder.toInstance(typeBuilder); + context.addTypeToSchema(ret, enumTypeDef); + context.addInnerTypedefType(enumTypeDef.getPath(), ret); + return ret; } /** @@ -785,22 +841,30 @@ abstract class AbstractTypeGenerator { throw new IllegalArgumentException("augment target not found: " + targetPath); } - GeneratedTypeBuilder targetTypeBuilder = findChildNodeByPath(targetSchemaNode.getPath()); - if (targetTypeBuilder == null) { - targetTypeBuilder = findCaseByPath(targetSchemaNode.getPath()); - } - if (targetTypeBuilder == null) { - throw new NullPointerException("Target type not yet generated: " + targetSchemaNode); + if (targetSchemaNode instanceof ChoiceSchemaNode) { + final GeneratedTypeBuilder builder = findChildNodeByPath(targetSchemaNode.getPath()); + checkState(builder != null, "Choice target type not generated for %s", targetSchemaNode); + generateTypesFromAugmentedChoiceCases(context, builder.build(), (ChoiceSchemaNode) targetSchemaNode, + augSchema.getChildNodes(), null, false); + return; } - if (!(targetSchemaNode instanceof ChoiceSchemaNode)) { - final Type targetType = new ReferencedTypeImpl(targetTypeBuilder.getIdentifier()); - addRawAugmentGenTypeDefinition(context, targetType, augSchema, false); - + final JavaTypeName targetName; + if (targetSchemaNode instanceof CaseSchemaNode) { + final GeneratedTypeBuilder builder = findCaseByPath(targetSchemaNode.getPath()); + checkState(builder != null, "Case target type not generated for %s", targetSchemaNode); + targetName = builder.getIdentifier(); } else { - generateTypesFromAugmentedChoiceCases(context, targetTypeBuilder.build(), - (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(), null, false); + final GeneratedTypeBuilder builder = findChildNodeByPath(targetSchemaNode.getPath()); + if (builder == null) { + targetName = findAliasByPath(targetSchemaNode.getPath()); + checkState(targetName != null, "Target type not yet generated: %s", targetSchemaNode); + } else { + targetName = builder.getIdentifier(); + } } + + addRawAugmentGenTypeDefinition(context, new ReferencedTypeImpl(targetName), augSchema, false); } private void usesAugmentationToGenTypes(final ModuleContext context, final AugmentationSchemaNode augSchema, @@ -859,11 +923,37 @@ abstract class AbstractTypeGenerator { private DataSchemaNode findOriginalTargetFromGrouping(final SchemaPath targetPath, final UsesNode parentUsesNode) { SchemaNode result = findUsedGrouping(parentUsesNode); for (final QName node : targetPath.getPathFromRoot()) { + // FIXME: this dispatch is rather ugly, we probably want to refactor it a bit if (result instanceof DataNodeContainer) { final QName resultNode = node.withModule(result.getQName().getModule()); - result = ((DataNodeContainer) result).getDataChildByName(resultNode); + + SchemaNode found = ((DataNodeContainer) result).getDataChildByName(resultNode); + if (found == null) { + if (result instanceof ActionNodeContainer) { + found = ((ActionNodeContainer) result).findAction(resultNode).orElse(null); + } + if (found == null && result instanceof NotificationNodeContainer) { + found = ((NotificationNodeContainer) result).findNotification(resultNode).orElse(null); + } + } + result = found; } else if (result instanceof ChoiceSchemaNode) { result = findNamedCase((ChoiceSchemaNode) result, node.getLocalName()); + } else if (result instanceof ActionDefinition) { + final ActionDefinition action = (ActionDefinition) result; + final QName resultNode = node.withModule(result.getQName().getModule()); + + final ContainerSchemaNode input = action.getInput(); + final ContainerSchemaNode output = action.getOutput(); + if (resultNode.equals(input.getQName())) { + result = input; + } else if (resultNode.equals(output.getQName())) { + result = output; + } else { + result = null; + } + } else if (result != null) { + throw new IllegalStateException("Cannot handle " + result); } } if (result == null) { @@ -926,17 +1016,20 @@ 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()) { context.addTypeToAugmentation(augTypeBuilder, augSchema); - } + context.addAugmentType(augTypeBuilder); return augTypeBuilder; } @@ -1053,7 +1146,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(), @@ -1081,11 +1174,11 @@ abstract class AbstractTypeGenerator { private void choiceToGeneratedType(final ModuleContext context, final GeneratedTypeBuilder parent, final ChoiceSchemaNode choiceNode, final boolean inGrouping) { if (!choiceNode.isAddedByUses()) { - final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition( + final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(context, 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(); @@ -1098,12 +1191,12 @@ abstract class AbstractTypeGenerator { private void opaqueToGeneratedType(final ModuleContext context, final GeneratedTypeBuilder parent, final DataSchemaNode anyNode) { if (!anyNode.isAddedByUses()) { - final GeneratedTypeBuilder anyxmlTypeBuilder = addRawInterfaceDefinition( + final GeneratedTypeBuilder anyxmlTypeBuilder = addRawInterfaceDefinition(context, JavaTypeName.create(packageNameForGeneratedType(context.modulePackageName(), anyNode.getPath()), 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); @@ -1135,7 +1228,7 @@ abstract class AbstractTypeGenerator { 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(); @@ -1318,13 +1411,8 @@ abstract class AbstractTypeGenerator { final TypeDefinition typeDef = CompatUtils.compatType(leaf); if (isInnerType(leaf, typeDef)) { if (typeDef instanceof EnumTypeDefinition) { - returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, inGrouping); final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef; - final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(), - typeBuilder, context); - if (enumBuilder != null) { - returnType = enumBuilder.toInstance(typeBuilder); - } + returnType = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(), typeBuilder, context); typeProvider.putReferencedType(leaf.getPath(), returnType); } else if (typeDef instanceof UnionTypeDefinition) { final UnionTypeDefinition unionDef = (UnionTypeDefinition)typeDef; @@ -1338,13 +1426,25 @@ abstract class AbstractTypeGenerator { returnType = genTOBuilder.build(); } } 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 + // It is constrained version of already declared type (inner declared type exists, only for 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, inGrouping); + final TypeDefinition baseOrDeclaredType = getBaseOrDeclaredType(typeDef); + // we need to try to lookup an already generated type in case the leafref is targetting a generated type + if (baseOrDeclaredType instanceof LeafrefTypeDefinition) { + final SchemaNode leafrefTarget = + typeProvider.getTargetForLeafref((LeafrefTypeDefinition) baseOrDeclaredType, leaf); + if (leafrefTarget instanceof TypedDataSchemaNode) { + returnType = context.getInnerType(((TypedDataSchemaNode) leafrefTarget).getType().getPath()); + } + } + if (returnType == null) { + returnType = typeProvider.javaTypeForSchemaDefinitionType(baseOrDeclaredType, leaf, + restrictions, inGrouping); + } + addPatternConstant(typeBuilder, leaf.getQName().getLocalName(), restrictions.getPatternConstraints()); } } else { @@ -1514,11 +1614,8 @@ abstract class AbstractTypeGenerator { Type returnType = null; if (typeDef.getBaseType() == null) { if (typeDef instanceof EnumTypeDefinition) { - returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, inGrouping); final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef; - final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName, - typeBuilder, context); - returnType = new ReferencedTypeImpl(enumBuilder.getIdentifier()); + returnType = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName, typeBuilder, context); typeProvider.putReferencedType(node.getPath(), returnType); } else if (typeDef instanceof UnionTypeDefinition) { final UnionTypeDefinition unionDef = (UnionTypeDefinition)typeDef; @@ -1610,7 +1707,7 @@ abstract class AbstractTypeGenerator { name = JavaTypeName.create(packageName, BindingMapping.getClassName(schemaNode.getQName())); } - final GeneratedTypeBuilder it = addRawInterfaceDefinition(name, schemaNode); + final GeneratedTypeBuilder it = addRawInterfaceDefinition(context, name, schemaNode); it.addImplementsType(baseInterface); if (!(schemaNode instanceof GroupingDefinition)) { it.addImplementsType(augmentable(it)); @@ -1641,7 +1738,8 @@ abstract class AbstractTypeGenerator { *
  • if schemaNode name is null
  • * */ - private GeneratedTypeBuilder addRawInterfaceDefinition(final JavaTypeName identifier, final SchemaNode schemaNode) { + private GeneratedTypeBuilder addRawInterfaceDefinition(final ModuleContext context, final JavaTypeName identifier, + final SchemaNode schemaNode) { checkArgument(schemaNode != null, "Data Schema Node cannot be NULL."); checkArgument(schemaNode.getQName() != null, "QName for Data Schema Node cannot be NULL."); final String schemaNodeName = schemaNode.getQName().getLocalName(); @@ -1649,10 +1747,9 @@ abstract class AbstractTypeGenerator { // FIXME: Validation of name conflict final GeneratedTypeBuilder newType = typeProvider.newGeneratedTypeBuilder(identifier); - final Module module = findParentModule(schemaContext, schemaNode); - qnameConstant(newType, JavaTypeName.create(BindingMapping.getRootPackageName(module.getQNameModule()), - BindingMapping.MODULE_INFO_CLASS_NAME), schemaNode.getQName().getLocalName()); + qnameConstant(newType, context.moduleInfoType(), schemaNode.getQName().getLocalName()); + final Module module = context.module(); addCodegenInformation(newType, module, schemaNode); newType.setSchemaPath(schemaNode.getPath()); newType.setModuleName(module.getName()); @@ -1701,7 +1798,7 @@ abstract class AbstractTypeGenerator { getterMethodName(node.getQName().getLocalName(), returnType)); getMethod.setReturnType(returnType); - annotateDeprecatedIfNecessary(node.getStatus(), getMethod); + annotateDeprecatedIfNecessary(node, getMethod); addComment(getMethod, node); return getMethod; @@ -1712,7 +1809,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); } /** @@ -1759,6 +1856,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); } } } @@ -1784,32 +1883,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; } /** @@ -1879,8 +1965,8 @@ abstract class AbstractTypeGenerator { for (final UsesNode usesNode : dataNodeContainer.getUses()) { final GeneratedTypeBuilder genType = findGroupingByPath(usesNode.getGroupingPath()); if (genType == null) { - throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for " - + builder.getName()); + throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + " is not resolved for " + + builder.getFullyQualifiedName()); } builder.addImplementsType(genType.build()); @@ -1888,6 +1974,16 @@ abstract class AbstractTypeGenerator { return builder; } + private JavaTypeName findAliasByPath(final SchemaPath path) { + for (final ModuleContext ctx : genCtx.values()) { + final JavaTypeName result = ctx.getAlias(path); + if (result != null) { + return result; + } + } + return null; + } + private GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path) { for (final ModuleContext ctx : genCtx.values()) { final GeneratedTypeBuilder result = ctx.getChildNode(path); @@ -1923,9 +2019,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); } }