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=05a1fedc3d8f2717c5c2694563b762fd361f90b5;hb=34bda8712a3306d2f0bfe5d85f70d4cbd9b6f407;hp=047716a10f96d6fef14aff548a322357f7c4a2ed;hpb=ce1e55484544d25297cb60cdfc6758e9b14945fb;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 047716a10f..05a1fedc3d 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 @@ -9,36 +9,60 @@ package org.opendaylight.mdsal.binding.generator.impl; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.computeDefaultSUID; import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.packageNameForAugmentedGeneratedType; import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.packageNameForGeneratedType; +import static org.opendaylight.mdsal.binding.model.util.BindingTypes.BASE_IDENTITY; 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.IDENTIFIABLE; -import static org.opendaylight.mdsal.binding.model.util.BindingTypes.IDENTIFIER; 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.FUTURE; -import static org.opendaylight.mdsal.binding.model.util.Types.VOID; -import static org.opendaylight.mdsal.binding.model.util.Types.typeForClass; +import static org.opendaylight.mdsal.binding.model.util.Types.STRING; +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.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; import java.util.Optional; 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.GeneratedTransferObject; @@ -47,6 +71,7 @@ import org.opendaylight.mdsal.binding.model.api.JavaTypeName; import org.opendaylight.mdsal.binding.model.api.ParameterizedType; import org.opendaylight.mdsal.binding.model.api.Restrictions; import org.opendaylight.mdsal.binding.model.api.Type; +import org.opendaylight.mdsal.binding.model.api.type.builder.AnnotableTypeBuilder; import org.opendaylight.mdsal.binding.model.api.type.builder.AnnotationTypeBuilder; import org.opendaylight.mdsal.binding.model.api.type.builder.EnumBuilder; import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedPropertyBuilder; @@ -56,22 +81,19 @@ 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.BindingTypes; 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; import org.opendaylight.mdsal.binding.yang.types.BaseYangTypes; import org.opendaylight.mdsal.binding.yang.types.GroupingDefinitionDependencySort; -import org.opendaylight.yangtools.yang.binding.BaseIdentity; -import org.opendaylight.yangtools.yang.binding.BindingMapping; -import org.opendaylight.yangtools.yang.binding.DataContainer; -import org.opendaylight.yangtools.yang.binding.RpcService; -import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; -import org.opendaylight.yangtools.yang.common.RpcResult; +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; @@ -80,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; @@ -88,16 +111,14 @@ 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.meta.EffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.meta.StatementSource; 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; @@ -110,8 +131,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; abstract class AbstractTypeGenerator { - private static final Logger LOG = LoggerFactory.getLogger(BindingGeneratorImpl.class); + private static final Logger LOG = LoggerFactory.getLogger(AbstractTypeGenerator.class); private static final Splitter COLON_SPLITTER = Splitter.on(':'); + private static final JavaTypeName DEPRECATED_ANNOTATION = JavaTypeName.create(Deprecated.class); + private static final JavaTypeName OVERRIDE_ANNOTATION = JavaTypeName.create(Override.class); + private static final Type LIST_STRING_TYPE = listTypeFor(BaseYangTypes.STRING_TYPE); /** * Comparator based on augment target path. @@ -147,10 +171,9 @@ abstract class AbstractTypeGenerator { private final Map genCtx = new HashMap<>(); /** - * Outer key represents the package name. Outer value represents map of all - * builders in the same package. Inner key represents the schema node name - * (in JAVA class/interface name format). Inner value represents instance of - * builder for schema node specified in key part. + * Outer key represents the package name. Outer value represents map of all builders in the same package. Inner key + * represents the schema node name (in JAVA class/interface name format). Inner value represents instance of builder + * for schema node specified in key part. */ private final Map> genTypeBuilders = new HashMap<>(); @@ -160,14 +183,20 @@ abstract class AbstractTypeGenerator { private final AbstractTypeProvider typeProvider; /** - * Holds reference to schema context to resolve data of augmented element - * when creating augmentation builder + * Holds reference to schema context to resolve data of augmented element when creating augmentation builder. */ private final SchemaContext schemaContext; - AbstractTypeGenerator(final SchemaContext context, final AbstractTypeProvider typeProvider) { + /** + * Holds renamed elements. + */ + private final Map renames; + + AbstractTypeGenerator(final SchemaContext context, final AbstractTypeProvider typeProvider, + final Map renames) { this.schemaContext = requireNonNull(context); this.typeProvider = requireNonNull(typeProvider); + this.renames = requireNonNull(renames); final List contextModules = ModuleDependencySort.sort(schemaContext.getModules()); final List contexts = new ArrayList<>(contextModules.size()); @@ -211,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; } @@ -241,20 +270,21 @@ abstract class AbstractTypeGenerator { if (typedef != null) { final Type type = typeProvider.generatedTypeForExtendedDefinitionType(typedef, typedef); if (type != null) { - context.addTypedefType(typedef.getPath(), type); + context.addTypedefType(typedef, type); context.addTypeToSchema(type,typedef); } } } } - private GeneratedTypeBuilder processDataSchemaNode(final ModuleContext context, final GeneratedTypeBuilder childOf, - final DataSchemaNode node) { + private GeneratedTypeBuilder processDataSchemaNode(final ModuleContext context, final Type baseInterface, + final DataSchemaNode node, final boolean inGrouping) { if (node.isAugmenting() || node.isAddedByUses()) { return null; } - final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(context, node, childOf); - annotateDeprecatedIfNecessary(node.getStatus(), genType); + final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(context, node, baseInterface); + defaultImplementedInterace(genType); + annotateDeprecatedIfNecessary(node, genType); final Module module = context.module(); genType.setModuleName(module.getName()); @@ -263,57 +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 GeneratedTypeBuilder childOf, final ContainerSchemaNode node) { - final GeneratedTypeBuilder genType = processDataSchemaNode(context, childOf, 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()); + 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 GeneratedTypeBuilder childOf, final ListSchemaNode node) { - final GeneratedTypeBuilder genType = processDataSchemaNode(context, childOf, node); + private void listToGenType(final ModuleContext context, final GeneratedTypeBuilder parent, + final Type baseInterface, final ListSchemaNode node, final boolean inGrouping) { + final GeneratedTypeBuilder genType = processDataSchemaNode(context, baseInterface, node, inGrouping); if (genType != null) { - constructGetter(parent, Types.listTypeFor(genType), node); - final List listKeys = listKeys(node); - final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(context, node); - if (genTOBuilder != null) { - final Type identifierMarker = Types.parameterizedTypeFor(IDENTIFIER, genType); - final Type identifiableMarker = Types.parameterizedTypeFor(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; } + final ParameterizedType listType = listTypeFor(genType); + 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); + 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); } } } @@ -389,6 +430,65 @@ abstract class AbstractTypeGenerator { return moduleDataTypeBuilder; } + 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(); + } else { + input = actionContainer(context, RPC_INPUT, action.getInput(), inGrouping); + output = actionContainer(context, RPC_OUTPUT, action.getOutput(), inGrouping); + } + + if (!(parentSchema instanceof GroupingDefinition)) { + // Parent is a non-grouping, hence we need to establish an Action instance, which can be completely + // identified by an InstanceIdentifier. We do not generate Actions for groupings as they are inexact, + // and do not capture an actual instantiation. + final QName qname = action.getQName(); + 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()); + + annotateDeprecatedIfNecessary(action, builder); + builder.addImplementsType(keyType != null ? keyedListAction(parent, keyType, input, output) + : action(parent, input, output)); + + addCodegenInformation(builder, context.module(), action); + context.addChildNodeType(action, builder); + } + } + } + + private Optional findOrigAction(final DataNodeContainer parent, final ActionDefinition action) { + for (UsesNode uses : parent.getUses()) { + final GroupingDefinition grp = findUsedGrouping(uses); + final Optional found = grp.findAction(action.getQName()); + if (found.isPresent()) { + final ActionDefinition result = found.get(); + return result.isAddedByUses() ? findOrigAction(grp, result) : found; + } + } + + return Optional.empty(); + } + + private GeneratedType actionContainer(final ModuleContext context, final Type baseInterface, + final ContainerSchemaNode schema, final boolean inGrouping) { + final GeneratedTypeBuilder genType = processDataSchemaNode(context, baseInterface, schema, inGrouping); + resolveDataSchemaNodes(context, genType, genType, schema.getChildNodes(), inGrouping); + return genType.build(); + } + /** * Converts all RPCs input and output substatements of the module * to the list of Type objects. In addition are to containers @@ -415,62 +515,41 @@ abstract class AbstractTypeGenerator { } final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(context, "Service"); - interfaceBuilder.addImplementsType(Types.typeForClass(RpcService.class)); + interfaceBuilder.addImplementsType(RPC_SERVICE); addCodegenInformation(interfaceBuilder, module, "RPCs", rpcDefinitions); 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); - final ContainerSchemaNode input = rpc.getInput(); - final ContainerSchemaNode output = rpc.getOutput(); // Do not refer to annotation class, as it may not be available at runtime - method.addAnnotation("javax.annotation", "CheckReturnValue"); - - //in case of implicit RPC input (StatementSource.CONTEXT), - // stay compatible (no input argument generated) - if (input != null && isExplicitStatement(input)) { - final Type inTypeInstance = createRpcContainer(context, rpcName, rpc, input); - method.addParameter(inTypeInstance, "input"); - } - - final Type outTypeInstance; - //in case of implicit RPC output (StatementSource.CONTEXT), - //stay compatible (Future> return type generated) - if (output != null && isExplicitStatement(output)) { - outTypeInstance = createRpcContainer(context, rpcName, rpc, output); - } else { - outTypeInstance = VOID; - } - - final Type rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult.class), outTypeInstance); + method.addAnnotation("edu.umd.cs.findbugs.annotations", "CheckReturnValue"); addComment(method, rpc); - method.setReturnType(Types.parameterizedTypeFor(FUTURE, rpcRes)); + method.addParameter( + createRpcContainer(context, rpcName, rpc, verifyNotNull(rpc.getInput()), RPC_INPUT), "input"); + method.setReturnType(listenableFutureTypeFor( + rpcResult(createRpcContainer(context, rpcName, rpc, verifyNotNull(rpc.getOutput()), RPC_OUTPUT)))); } } context.addTopLevelNodeType(interfaceBuilder); } - private static boolean isExplicitStatement(final ContainerSchemaNode node) { - return node instanceof EffectiveStatement - && ((EffectiveStatement) node).getDeclared().getStatementSource() == StatementSource.DECLARATION; - } - private Type createRpcContainer(final ModuleContext context, final String rpcName, final RpcDefinition rpc, - final ContainerSchemaNode schema) { - processUsesAugments(schema, context); + final ContainerSchemaNode schema, final Type type) { + processUsesAugments(schema, context, false); final GeneratedTypeBuilder outType = addRawInterfaceDefinition( JavaTypeName.create(context.modulePackageName(), rpcName + BindingMapping.getClassName(schema.getQName())), schema); addImplementedInterfaceFromUses(schema, outType); - outType.addImplementsType(DATA_OBJECT); + 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(); } @@ -500,25 +579,26 @@ abstract class AbstractTypeGenerator { } final GeneratedTypeBuilder listenerInterface = moduleTypeBuilder(context, "Listener"); - listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER); + listenerInterface.addImplementsType(NOTIFICATION_LISTENER); for (final NotificationDefinition notification : notifications) { if (notification != null) { - processUsesAugments(notification, context); + processUsesAugments(notification, context, false); final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition( - context.modulePackageName(), notification, null, context); - annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface); + context.modulePackageName(), notification, DATA_OBJECT, context); + 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); } } @@ -526,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. @@ -567,20 +681,29 @@ abstract class AbstractTypeGenerator { if (identity == null) { return; } - final GeneratedTypeBuilder newType = typeProvider.newGeneratedTypeBuilder(JavaTypeName.create( - packageNameForGeneratedType(context.modulePackageName(), identity.getPath()), - BindingMapping.getClassName(identity.getQName()))); + + JavaTypeName name = renames.get(identity); + if (name == null) { + name = JavaTypeName.create(packageNameForGeneratedType(context.modulePackageName(), identity.getPath()), + BindingMapping.getClassName(identity.getQName())); + } + + final GeneratedTypeBuilder newType = typeProvider.newGeneratedTypeBuilder(name); final Set baseIdentities = identity.getBaseIdentities(); - if (baseIdentities.isEmpty()) { - final GeneratedTOBuilder gto = typeProvider.newGeneratedTOBuilder(JavaTypeName.create(BaseIdentity.class)); - newType.addImplementsType(gto.build()); - } else { + if (!baseIdentities.isEmpty()) { for (IdentitySchemaNode baseIdentity : baseIdentities) { - final QName qname = baseIdentity.getQName(); - final GeneratedTransferObject gto = typeProvider.newGeneratedTOBuilder(JavaTypeName.create( - BindingMapping.getRootPackageName(qname.getModule()), BindingMapping.getClassName(qname))).build(); + JavaTypeName base = renames.get(baseIdentity); + if (base == null) { + final QName qname = baseIdentity.getQName(); + base = JavaTypeName.create(BindingMapping.getRootPackageName(qname.getModule()), + BindingMapping.getClassName(qname)); + } + + final GeneratedTransferObject gto = typeProvider.newGeneratedTOBuilder(base).build(); newType.addImplementsType(gto); } + } else { + newType.addImplementsType(BASE_IDENTITY); } final Module module = context.module(); @@ -588,15 +711,16 @@ abstract class AbstractTypeGenerator { newType.setModuleName(module.getName()); newType.setSchemaPath(identity.getPath()); - qnameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, identity.getQName()); + qnameConstant(newType, JavaTypeName.create(context.modulePackageName(), BindingMapping.MODULE_INFO_CLASS_NAME), + identity.getQName().getLocalName()); - context.addIdentityType(identity.getQName(), newType); + context.addIdentityType(identity, newType); } - - private static Constant qnameConstant(final GeneratedTypeBuilderBase toBuilder, final String constantName, - final QName name) { - return toBuilder.addConstant(typeForClass(QName.class), constantName, name); + private static Constant qnameConstant(final GeneratedTypeBuilderBase toBuilder, + final JavaTypeName yangModuleInfo, final String localName) { + return toBuilder.addConstant(QNAME, BindingMapping.QNAME_STATIC_FIELD_NAME, + new SimpleImmutableEntry<>(yangModuleInfo, localName)); } /** @@ -617,32 +741,26 @@ 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); - context.addGroupingType(grouping.getPath(), genType); - resolveDataSchemaNodes(context, genType, genType, grouping.getChildNodes()); + narrowImplementedInterface(genType); + annotateDeprecatedIfNecessary(grouping, genType); + context.addGroupingType(grouping, genType); + resolveDataSchemaNodes(context, genType, genType, grouping.getChildNodes(), true); groupingsToGenTypes(context, grouping.getGroupings()); - processUsesAugments(grouping, context); + processUsesAugments(grouping, context, true); + actionsToGenType(context, genType, grouping, null, true); + notificationsToGenType(context, genType, grouping, null, true); } } /** - * Adds enumeration builder created from enumTypeDef to - * typeBuilder. - * - * Each enumTypeDef item is added to builder with its name and - * value. + * Adds enumeration builder created from enumTypeDef to typeBuilder. Each + * enumTypeDef item is added to builder with its name and value. * - * @param enumTypeDef - * EnumTypeDefinition contains enum data - * @param enumName - * string contains name which will be assigned to enumeration - * builder - * @param typeBuilder - * GeneratedTypeBuilder to which will be enum builder assigned - * @param module - * Module in which type should be generated - * @return enumeration builder which contains data from - * enumTypeDef + * @param enumTypeDef EnumTypeDefinition contains enum data + * @param enumName string contains name which will be assigned to enumeration builder + * @param typeBuilder GeneratedTypeBuilder to which will be enum builder assigned + * @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, final GeneratedTypeBuilder typeBuilder, final ModuleContext context) { @@ -659,16 +777,10 @@ abstract class AbstractTypeGenerator { /** * Generates type builder for module. * - * @param module - * Module which is source of package name for generated type - * builder - * @param postfix - * string which is added to the module class name representation - * as suffix - * @return instance of GeneratedTypeBuilder which represents - * module. - * @throws IllegalArgumentException - * if module is null + * @param module Module which is source of package name for generated type builder + * @param postfix string which is added to the module class name representation as suffix + * @return instance of GeneratedTypeBuilder which represents module. + * @throws IllegalArgumentException if module is null */ private GeneratedTypeBuilder moduleTypeBuilder(final ModuleContext context, final String postfix) { final Module module = context.module(); @@ -682,20 +794,13 @@ abstract class AbstractTypeGenerator { } /** - * Converts augSchema to list of Type which - * contains generated type for augmentation. In addition there are also - * generated types for all containers, list and choices which are child of - * augSchema node or a generated types for cases are added if - * augmented node is choice. + * Converts augSchema to list of Type which contains generated type for augmentation. + * In addition there are also generated types for all containers, list and choices which are child of + * augSchema node or a generated types for cases are added if augmented node is choice. * - * @param augmentPackageName - * string with the name of the package to which the augmentation - * belongs - * @param augSchema - * AugmentationSchema which is contains data about augmentation - * (target path, childs...) - * @param module - * current module + * @param augmentPackageName string with the name of the package to which the augmentation belongs + * @param augSchema AugmentationSchema which is contains data about augmentation (target path, childs...) + * @param module current module * @throws IllegalArgumentException *
    *
  • if augmentPackageName equals null
  • @@ -709,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; @@ -737,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) { @@ -771,33 +876,35 @@ 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); + } + } + + 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. * - * @param targetPath - * node path - * @param parentUsesNode - * parent of uses node + * @param targetPath node path + * @param parentUsesNode parent of uses node * @return node from its original location in grouping */ private DataSchemaNode findOriginalTargetFromGrouping(final SchemaPath targetPath, final UsesNode parentUsesNode) { - final SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, parentUsesNode.getGroupingPath() - .getPathFromRoot()); - if (!(targetGrouping instanceof GroupingDefinition)) { - throw new IllegalArgumentException("Failed to generate code for augment in " + parentUsesNode); - } - - SchemaNode result = targetGrouping; + SchemaNode result = findUsedGrouping(parentUsesNode); for (final QName node : targetPath.getPathFromRoot()) { if (result instanceof DataNodeContainer) { final QName resultNode = node.withModule(result.getQName().getModule()); @@ -836,34 +943,21 @@ abstract class AbstractTypeGenerator { } /** - * Returns a generated type builder for an augmentation. - * - * The name of the type builder is equal to the name of augmented node with - * serial number as suffix. + * Returns a generated type builder for an augmentation. The name of the type builder is equal to the name + * of augmented node with serial number as suffix. * - * @param context - * current module - * @param augmentPackageName - * string with contains the package name to which the augment - * belongs - * @param basePackageName - * string with the package name to which the augmented node - * belongs - * @param targetTypeRef - * target type - * @param augSchema - * augmentation schema which contains data about the child nodes - * and uses of augment + * @param context current module + * @param augmentPackageName string with contains the package name to which the augment belongs + * @param basePackageName string with the package name to which the augmented node belongs + * @param targetTypeRef target type + * @param augSchema augmentation schema which contains data about the child nodes and uses of augment * @return generated type builder for augment */ private GeneratedTypeBuilder addRawAugmentGenTypeDefinition(final ModuleContext context, final String augmentPackageName, final Type targetTypeRef, - final AugmentationSchemaNode augSchema) { - Map augmentBuilders = genTypeBuilders.get(augmentPackageName); - if (augmentBuilders == null) { - augmentBuilders = new HashMap<>(); - genTypeBuilders.put(augmentPackageName, augmentBuilders); - } + final AugmentationSchemaNode augSchema, final boolean inGrouping) { + Map augmentBuilders = + genTypeBuilders.computeIfAbsent(augmentPackageName, k -> new HashMap<>()); final String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes()); String augTypeName; @@ -877,31 +971,32 @@ abstract class AbstractTypeGenerator { JavaTypeName.create(augmentPackageName, augTypeName)); augTypeBuilder.addImplementsType(DATA_OBJECT); - augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef)); - annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder); + defaultImplementedInterace(augTypeBuilder); + + augTypeBuilder.addImplementsType(augmentation(targetTypeRef)); + annotateDeprecatedIfNecessary(augSchema, augTypeBuilder); addImplementedInterfaceFromUses(augSchema, augTypeBuilder); - augSchemaNodeToMethods(context,augTypeBuilder, 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); } - /** - * - * @param unknownSchemaNodes - * @return nodeParameter of UnknownSchemaNode - */ private static String getAugmentIdentifier(final List unknownSchemaNodes) { for (final UnknownSchemaNode unknownSchemaNode : unknownSchemaNodes) { final QName nodeType = unknownSchemaNode.getNodeType(); @@ -914,15 +1009,11 @@ abstract class AbstractTypeGenerator { } /** - * Returns first unique name for the augment generated type builder. The - * generated type builder name for augment consists from name of augmented - * node and serial number of its augmentation. + * Returns first unique name for the augment generated type builder. The generated type builder name for augment + * consists from name of augmented node and serial number of its augmentation. * - * @param builders - * map of builders which were created in the package to which the - * augmentation belongs - * @param genTypeName - * string with name of augmented node + * @param builders map of builders which were created in the package to which the augmentation belongs + * @param genTypeName string with name of augmented node * @return string with unique name for augmentation builder */ private static String augGenTypeName(final Map builders, final String genTypeName) { @@ -936,34 +1027,27 @@ abstract class AbstractTypeGenerator { } /** - * Adds the methods to typeBuilder which represent subnodes of - * node for which typeBuilder was created. + * Adds the methods to typeBuilder which represent subnodes of node for which typeBuilder + * was created. The subnodes aren't mapped to the methods if they are part of grouping or augment (in this case are + * already part of them). * - * The subnodes aren't mapped to the methods if they are part of grouping or - * augment (in this case are already part of them). - * - * @param module - * current module - * @param parent - * generated type builder which represents any node. The subnodes - * of this node are added to the typeBuilder as - * methods. The subnode can be of type leaf, leaf-list, list, - * container, choice. - * @param childOf - * parent type - * @param schemaNodes - * set of data schema nodes which are the children of the node - * for which typeBuilder was created - * @return generated type builder which is the same builder as input - * parameter. The getter methods (representing child nodes) could be - * added to it. + * @param module current module + * @param parent generated type builder which represents any node. The subnodes of this node are added + * to the typeBuilder as methods. The subnode can be of type leaf, leaf-list, list, + * container, choice. + * @param childOf parent type + * @param schemaNodes set of data schema nodes which are the children of the node for which + * typeBuilder was created + * @return generated type builder which is the same builder as input parameter. The getter methods (representing + * child nodes) could be added to it. */ private GeneratedTypeBuilder resolveDataSchemaNodes(final ModuleContext context, final GeneratedTypeBuilder parent, - final GeneratedTypeBuilder 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, childOf); + addSchemaNodeToBuilderAsMethod(context, schemaNode, parent, baseInterface, inGrouping); } } } @@ -971,32 +1055,27 @@ abstract class AbstractTypeGenerator { } /** - * Adds the methods to typeBuilder what represents subnodes of - * node for which typeBuilder was created. + * Adds the methods to typeBuilder what represents subnodes of node for which typeBuilder + * was created. * - * @param module - * current module - * @param typeBuilder - * generated type builder which represents any node. The subnodes - * of this node are added to the typeBuilder as - * methods. The subnode can be of type leaf, leaf-list, list, - * container, choice. - * @param childOf - * parent type - * @param schemaNodes - * set of data schema nodes which are the children of the node - * for which typeBuilder was created - * @return generated type builder which is the same object as the input - * parameter typeBuilder. The getter method could be - * added to it. + * @param module current module + * @param typeBuilder generated type builder which represents any node. The subnodes of this node are added + * to the typeBuilder as methods. The subnode can be of type leaf, leaf-list, list, + * container, choice. + * @param childOf parent type + * @param schemaNodes set of data schema nodes which are the children of the node for which typeBuilder + * was created + * @return generated type builder which is the same object as the input parameter typeBuilder. + * The getter method could be added to it. */ private GeneratedTypeBuilder augSchemaNodeToMethods(final ModuleContext context, - final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, - 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, childOf); + addSchemaNodeToBuilderAsMethod(context, schemaNode, typeBuilder, baseInterface, inGrouping); } } } @@ -1004,35 +1083,29 @@ abstract class AbstractTypeGenerator { } /** - * Adds to typeBuilder a method which is derived from - * schemaNode. + * Adds to typeBuilder a method which is derived from schemaNode. * - * @param node - * data schema node which is added to typeBuilder as - * a method - * @param typeBuilder - * generated type builder to which is schemaNode - * added as a method. - * @param childOf - * parent type - * @param module - * current module + * @param node data schema node which is added to typeBuilder as a method + * @param typeBuilder generated type builder to which is schemaNode added as a method. + * @param childOf parent type + * @param module current module */ private void addSchemaNodeToBuilderAsMethod(final ModuleContext context, final DataSchemaNode node, - final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf) { + 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, childOf, (ContainerSchemaNode) node); + containerToGenType(context, typeBuilder, baseInterface, (ContainerSchemaNode) node, inGrouping); } else if (node instanceof ListSchemaNode) { - listToGenType(context, typeBuilder, childOf, (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()); } @@ -1040,22 +1113,15 @@ abstract class AbstractTypeGenerator { } /** - * Converts choiceNode to the list of generated types for - * choice and its cases. - * - * The package names for choice and for its cases are created as - * concatenation of the module package (basePackageName) and - * names of all parents node. + * Converts choiceNode to the list of generated types for choice and its cases. The package names + * for choice and for its cases are created as concatenation of the module package (basePackageName) + * and names of all parents node. * - * @param context - * current module - * @param basePackageName - * string with the module package name - * @param parent - * parent type - * @param choiceNode - * choice node which is mapped to generated type. Also child - * nodes - cases are mapped to generated types. + * @param context current module + * @param basePackageName string with the module package name + * @param parent parent type + * @param choiceNode choice node which is mapped to generated type. Also child nodes - cases are mapped to generated + * types. * @throws IllegalArgumentException *
      *
    • if basePackageName is null
    • @@ -1063,35 +1129,46 @@ 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); - constructGetter(parent, choiceTypeBuilder, choiceNode); - choiceTypeBuilder.addImplementsType(typeForClass(DataContainer.class)); - annotateDeprecatedIfNecessary(choiceNode.getStatus(), choiceTypeBuilder); + choiceTypeBuilder.addImplementsType(choiceIn(parent)); + annotateDeprecatedIfNecessary(choiceNode, choiceTypeBuilder); context.addChildNodeType(choiceNode, choiceTypeBuilder); - generateTypesFromChoiceCases(context, choiceTypeBuilder.build(), choiceNode); + + final GeneratedType choiceType = choiceTypeBuilder.build(); + 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 isn't added through augment or uses is created generated type builder. - * The package names for the builder is created as concatenation of the module package and names of all parents - * nodes of the concrete case. There is also relation "implements type" between every case builder - * and choice type + * 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 + * created as concatenation of the module package and names of all parents nodes of the concrete case. There + * is also relation "implements type" between every case builder and choice type * - * @param context - * current module context - * @param refChoiceType - * type which represents superior case - * @param choiceNode - * choice case node which is mapped to generated type + * @param context current module context + * @param refChoiceType type which represents superior case + * @param choiceNode choice case node which is mapped to generated type * @throws IllegalArgumentException *
      *
    • if refChoiceType equals null
    • @@ -1099,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."); @@ -1107,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(); @@ -1137,38 +1215,33 @@ abstract class AbstractTypeGenerator { } checkState(parent != null, "Could not find Choice node parent %s", choiceNodeParentPath); - GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.getPath()); + Type childOfType = findChildNodeByPath(parent.getPath()); 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); } } /** - * Generates list of generated types for all the cases of a choice which are - * added to the choice through the augment. + * Generates list of generated types for all the cases of a choice which are added to the choice through + * the augment. * - * @param module - * current module - * @param basePackageName - * string contains name of package to which augment belongs. If - * an augmented choice is from an other package (pcg1) than an - * augmenting choice (pcg2) then case's of the augmenting choice - * will belong to pcg2. - * @param targetType - * Type which represents target choice - * @param targetNode - * node which represents target choice - * @param augmentedNodes - * set of choice case nodes for which is checked if are/aren't - * added to choice through augmentation + * @param module current module + * @param basePackageName string contains name of package to which augment belongs. If an augmented choice is + * from an other package (pcg1) than an augmenting choice (pcg2) then case's + * of the augmenting choice will belong to pcg2. + * @param targetType Type which represents target choice + * @param targetNode node which represents target choice + * @param augmentedNodes set of choice case nodes for which is checked if are/are not added to choice through + * augmentation * @throws IllegalArgumentException *
      *
    • if basePackageName is null
    • @@ -1176,9 +1249,11 @@ abstract class AbstractTypeGenerator { *
    • if augmentedNodes is null
    • *
    */ + // 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 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."); @@ -1186,25 +1261,7 @@ abstract class AbstractTypeGenerator { if (caseNode != null) { final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(context, caseNode); caseTypeBuilder.addImplementsType(targetType); - - SchemaNode parent; - final SchemaPath nodeSp = targetNode.getPath(); - parent = findDataSchemaNode(schemaContext, nodeSp.getParent()); - - GeneratedTypeBuilder childOfType = null; - if (parent instanceof Module) { - childOfType = moduleContext(((Module) parent).getQNameModule()).getModuleNode(); - } else if (parent instanceof CaseSchemaNode) { - childOfType = findCaseByPath(parent.getPath()); - } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) { - childOfType = findChildNodeByPath(parent.getPath()); - } else if (parent instanceof GroupingDefinition) { - childOfType = findGroupingByPath(parent.getPath()); - } - - if (childOfType == null) { - throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode); - } + defaultImplementedInterace(caseTypeBuilder); CaseSchemaNode node = null; final String caseLocalName = caseNode.getQName().getLocalName(); @@ -1224,7 +1281,8 @@ abstract class AbstractTypeGenerator { } final Iterable childNodes = node.getChildNodes(); if (childNodes != null) { - resolveDataSchemaNodes(context, caseTypeBuilder, childOfType, childNodes); + resolveDataSchemaNodes(context, caseTypeBuilder, findChildOfType(targetNode), childNodes, + inGrouping); } context.addCaseType(caseNode.getPath(), caseTypeBuilder); context.addChoiceToCaseMapping(targetType, caseTypeBuilder, node); @@ -1232,6 +1290,30 @@ abstract class AbstractTypeGenerator { } } + private GeneratedTypeBuilder findChildOfType(final ChoiceSchemaNode targetNode) { + final SchemaPath nodePath = targetNode.getPath(); + final SchemaPath parentSp = nodePath.getParent(); + if (parentSp.getParent() == null) { + return moduleContext(nodePath.getLastComponent().getModule()).getModuleNode(); + } + + final SchemaNode parent = findDataSchemaNode(schemaContext, parentSp); + GeneratedTypeBuilder childOfType = null; + if (parent instanceof CaseSchemaNode) { + childOfType = findCaseByPath(parent.getPath()); + } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) { + childOfType = findChildNodeByPath(parent.getPath()); + } else if (parent instanceof GroupingDefinition) { + childOfType = findGroupingByPath(parent.getPath()); + } + + if (childOfType == null) { + throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode); + } + + return childOfType; + } + private static CaseSchemaNode findNamedCase(final ChoiceSchemaNode choice, final String caseName) { final List cases = choice.findCaseNodes(caseName); return cases.isEmpty() ? null : cases.get(0); @@ -1256,23 +1338,17 @@ abstract class AbstractTypeGenerator { if (!patternConstraints.isEmpty()) { final StringBuilder field = new StringBuilder().append(TypeConstants.PATTERN_CONSTANT_NAME).append("_") .append(BindingMapping.getPropertyName(leafName)); - typeBuilder.addConstant(Types.listTypeFor(BaseYangTypes.STRING_TYPE), field.toString(), + typeBuilder.addConstant(LIST_STRING_TYPE, field.toString(), typeProvider.resolveRegExpressions(patternConstraints)); } } /** - * Converts leaf to the getter method which is added to - * typeBuilder. + * Converts leaf to the getter method which is added to typeBuilder. * - * @param typeBuilder - * generated type builder to which is added getter method as - * leaf mapping - * @param leaf - * leaf schema node which is mapped as getter method which is - * added to typeBuilder - * @param module - * Module in which type was defined + * @param typeBuilder generated type builder to which is added getter method as leaf mapping + * @param leaf leaf schema node which is mapped as getter method which is added to typeBuilder + * @param module Module in which type was defined * @return boolean value *
      *
    • false - if leaf or typeBuilder are @@ -1281,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; } @@ -1289,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); @@ -1301,13 +1377,10 @@ abstract class AbstractTypeGenerator { } typeProvider.putReferencedType(leaf.getPath(), returnType); } else if (typeDef instanceof UnionTypeDefinition) { - GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder((UnionTypeDefinition) typeDef, typeBuilder, leaf, - parentModule); - if (genTOBuilder != null) { - returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule); - // Store the inner type within the union so that we can find the reference for it - context.addInnerTypedefType(typeDef.getPath(), returnType); - } + final UnionTypeDefinition unionDef = (UnionTypeDefinition)typeDef; + returnType = addTOToTypeBuilder(unionDef, typeBuilder, leaf, parentModule); + // Store the inner type within the union so that we can find the reference for it + context.addInnerTypedefType(typeDef.getPath(), returnType); } else if (typeDef instanceof BitsTypeDefinition) { GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder((BitsTypeDefinition) typeDef, typeBuilder, leaf, parentModule); @@ -1321,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()); } @@ -1381,7 +1454,7 @@ abstract class AbstractTypeGenerator { + nodeParam); } - final AnnotationTypeBuilder rc = getter.addAnnotation(JavaTypeName.create(RoutingContext.class)); + final AnnotationTypeBuilder rc = getter.addAnnotation(ROUTING_CONTEXT); final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath()); final String genTypeName = BindingMapping.getClassName(identity.getQName().getLocalName()); rc.addParameter("value", packageName + "." + genTypeName + ".class"); @@ -1411,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()); @@ -1434,19 +1507,12 @@ abstract class AbstractTypeGenerator { } /** - * Converts leaf schema node to property of generated TO - * builder. + * Converts leaf schema node to property of generated TO builder. * - * @param toBuilder - * generated TO builder to which is leaf added as - * property - * @param leaf - * leaf schema node which is added to toBuilder as - * property - * @param returnType - * property type - * @param isReadOnly - * boolean value which says if leaf property is|isn't read only + * @param toBuilder generated TO builder to which is leaf added as property + * @param leaf leaf schema node which is added to toBuilder as property + * @param returnType property type + * @param isReadOnly boolean value which says if leaf property is|isn't read only * @return boolean value *
      *
    • false - if leaf, toBuilder or leaf @@ -1472,15 +1538,10 @@ abstract class AbstractTypeGenerator { } /** - * Converts node leaf list schema node to getter method of - * typeBuilder. + * Converts node leaf list schema node to getter method of typeBuilder. * - * @param typeBuilder - * generated type builder to which is node added as - * getter method - * @param node - * leaf list schema node which is added to - * typeBuilder as getter method + * @param typeBuilder generated type builder to which is node added as getter method + * @param node leaf list schema node which is added to typeBuilder as getter method * @param module module * @return boolean value *
        @@ -1490,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; } @@ -1503,170 +1564,124 @@ 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); returnType = new ReferencedTypeImpl(enumBuilder.getIdentifier()); typeProvider.putReferencedType(node.getPath(), returnType); } else if (typeDef instanceof UnionTypeDefinition) { - final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder((UnionTypeDefinition)typeDef, typeBuilder, - node, parentModule); - if (genTOBuilder != null) { - returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule); - } + final UnionTypeDefinition unionDef = (UnionTypeDefinition)typeDef; + returnType = addTOToTypeBuilder(unionDef, typeBuilder, node, parentModule); } else if (typeDef instanceof BitsTypeDefinition) { final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder((BitsTypeDefinition)typeDef, typeBuilder, node, parentModule); 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()); } - final ParameterizedType listType = Types.listTypeFor(returnType); - constructGetter(typeBuilder, listType, node); + constructGetter(typeBuilder, listTypeFor(returnType), node); return true; } - private Type createReturnTypeForUnion(final GeneratedTOBuilder genTOBuilder, final TypeDefinition typeDef, + private Type createReturnTypeForUnion(final GeneratedTOBuilder genTOBuilder, final UnionTypeDefinition typeDef, final GeneratedTypeBuilder typeBuilder, final Module parentModule) { - final GeneratedTOBuilder returnType = typeProvider.newGeneratedTOBuilder(genTOBuilder.getIdentifier()); - - addCodegenInformation(returnType, parentModule, typeDef); - returnType.setSchemaPath(typeDef.getPath()); - returnType.setModuleName(parentModule.getName()); + final GeneratedTOBuilder returnTypeBuilder = typeProvider.newGeneratedTOBuilder(genTOBuilder.getIdentifier()); + returnTypeBuilder.setIsUnion(true); + addCodegenInformation(returnTypeBuilder, parentModule, typeDef); + returnTypeBuilder.setSchemaPath(typeDef.getPath()); + returnTypeBuilder.setModuleName(parentModule.getName()); + final GeneratedTransferObject returnType = returnTypeBuilder.build(); genTOBuilder.setTypedef(true); genTOBuilder.setIsUnion(true); AbstractTypeProvider.addUnitsToGenTO(genTOBuilder, typeDef.getUnits().orElse(null)); - - - final GeneratedTOBuilder unionBuilder = createUnionBuilder(genTOBuilder, typeBuilder); - - - final MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance"); - method.setReturnType(returnType); - method.addParameter(Types.STRING, "defaultValue"); - method.setAccessModifier(AccessModifier.PUBLIC); - method.setStatic(true); - - final Set types = typeProvider.getAdditionalTypes().get(parentModule); - if (types == null) { - typeProvider.getAdditionalTypes().put(parentModule, - Sets.newHashSet(unionBuilder.build())); - } else { - types.add(unionBuilder.build()); - } - return returnType.build(); + createUnionBuilder(genTOBuilder, typeBuilder, returnType, parentModule); + return returnType; } - private GeneratedTOBuilder createUnionBuilder(final GeneratedTOBuilder genTOBuilder, - final GeneratedTypeBuilder typeBuilder) { + private void createUnionBuilder(final GeneratedTOBuilder genTOBuilder, final GeneratedTypeBuilder typeBuilder, + final GeneratedTransferObject returnType, final Module parentModule) { // Append enclosing path hierarchy without dots final StringBuilder sb = new StringBuilder(); genTOBuilder.getIdentifier().localNameComponents().forEach(sb::append); final GeneratedTOBuilder unionBuilder = typeProvider.newGeneratedTOBuilder( JavaTypeName.create(typeBuilder.getPackageName(), sb.append("Builder").toString())); unionBuilder.setIsUnionBuilder(true); - return unionBuilder; + + final MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance"); + method.setReturnType(returnType); + method.addParameter(STRING, "defaultValue"); + method.setAccessModifier(AccessModifier.PUBLIC); + method.setStatic(true); + + final GeneratedTransferObject unionBuilderType = unionBuilder.build(); + typeProvider.getAdditionalTypes().computeIfAbsent(parentModule, key -> new HashSet<>()).add(unionBuilderType); } private GeneratedTypeBuilder addDefaultInterfaceDefinition(final ModuleContext context, final SchemaNode schemaNode) { - return addDefaultInterfaceDefinition(context, schemaNode, null); + return addDefaultInterfaceDefinition(context, schemaNode, DATA_OBJECT); } private GeneratedTypeBuilder addDefaultInterfaceDefinition(final ModuleContext context, - final SchemaNode schemaNode, final GeneratedTypeBuilder childOf) { + final SchemaNode schemaNode, final Type baseInterface) { final String packageName = packageNameForGeneratedType(context.modulePackageName(), schemaNode.getPath()); - return addDefaultInterfaceDefinition(packageName, schemaNode, childOf, context); + return addDefaultInterfaceDefinition(packageName, schemaNode, baseInterface, context); } - /** - * Instantiates generated type builder with packageName and - * schemaNode. - * - * The new builder always implements - * {@link org.opendaylight.yangtools.yang.binding.DataObject DataObject}.
      - * If schemaNode is instance of GroupingDefinition it also - * implements {@link org.opendaylight.yangtools.yang.binding.Augmentable - * Augmentable}.
      + * Instantiates generated type builder with packageName and schemaNode. The new builder + * always implements {@link org.opendaylight.yangtools.yang.binding.DataObject DataObject}.
      + * If schemaNode is instance of GroupingDefinition it also implements + * {@link org.opendaylight.yangtools.yang.binding.Augmentable Augmentable}.
      * If schemaNode is instance of - * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer - * DataNodeContainer} it can also implement nodes which are specified in - * uses. + * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer DataNodeContainer} it can also implement nodes + * which are specified in uses. * - * @param packageName - * string with the name of the package to which - * schemaNode belongs. - * @param schemaNode - * schema node for which is created generated type builder - * @param parent - * parent type (can be null) + * @param packageName string with the name of the package to which schemaNode belongs. + * @param schemaNode schema node for which is created generated type builder + * @param parent parent type (can be null) * @return generated type builder schemaNode */ private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode, - final Type parent, final ModuleContext context) { - final GeneratedTypeBuilder it = addRawInterfaceDefinition( - JavaTypeName.create(packageName, BindingMapping.getClassName(schemaNode.getQName())), schemaNode); - if (parent == null) { - it.addImplementsType(DATA_OBJECT); - } else { - it.addImplementsType(BindingTypes.childOf(parent)); + final Type baseInterface, final ModuleContext context) { + JavaTypeName name = renames.get(schemaNode); + if (name == null) { + name = JavaTypeName.create(packageName, BindingMapping.getClassName(schemaNode.getQName())); } + + final GeneratedTypeBuilder it = addRawInterfaceDefinition(name, schemaNode); + it.addImplementsType(baseInterface); if (!(schemaNode instanceof GroupingDefinition)) { it.addImplementsType(augmentable(it)); } - if (schemaNode instanceof DataNodeContainer) { - groupingsToGenTypes(context, ((DataNodeContainer) schemaNode).getGroupings()); - addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it); + final DataNodeContainer containerSchema = (DataNodeContainer) schemaNode; + groupingsToGenTypes(context, containerSchema.getGroupings()); + addImplementedInterfaceFromUses(containerSchema, it); } return it; } /** - * Wraps the calling of the same overloaded method. - * - * @param packageName - * string with the package name to which returning generated type - * builder belongs - * @param schemaNode - * schema node which provide data about the schema node name - * @return generated type builder for schemaNode - */ - private GeneratedTypeBuilder addRawInterfaceDefinition(final ModuleContext context, final SchemaNode schemaNode, - final String prefix) { - return addRawInterfaceDefinition( - JavaTypeName.create(packageNameForGeneratedType(context.modulePackageName(), schemaNode.getPath()), - prefix + BindingMapping.getClassName(schemaNode.getQName())), schemaNode); - } - - /** - * Returns reference to generated type builder for specified - * schemaNode with packageName. - * - * Firstly the generated type builder is searched in - * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't - * found it is created and added to genTypeBuilders. + * Returns reference to generated type builder for specified schemaNode with packageName. + * Firstly the generated type builder is searched in {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. + * If it is not found it is created and added to genTypeBuilders. * - * @param packageName - * string with the package name to which returning generated type - * builder belongs - * @param schemaNode - * schema node which provide data about the schema node name - * @param prefix - * return type name prefix + * @param packageName string with the package name to which returning generated type builder belongs + * @param schemaNode schema node which provide data about the schema node name + * @param prefix return type name prefix * @return generated type builder for schemaNode * @throws IllegalArgumentException *
        @@ -1675,7 +1690,6 @@ abstract class AbstractTypeGenerator { *
      • if QName of schema node is null
      • *
      • if schemaNode name is null
      • *
      - * */ private GeneratedTypeBuilder addRawInterfaceDefinition(final JavaTypeName identifier, final SchemaNode schemaNode) { checkArgument(schemaNode != null, "Data Schema Node cannot be NULL."); @@ -1686,7 +1700,8 @@ abstract class AbstractTypeGenerator { // FIXME: Validation of name conflict final GeneratedTypeBuilder newType = typeProvider.newGeneratedTypeBuilder(identifier); final Module module = findParentModule(schemaContext, schemaNode); - qnameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName()); + qnameConstant(newType, JavaTypeName.create(BindingMapping.getRootPackageName(module.getQNameModule()), + BindingMapping.MODULE_INFO_CLASS_NAME), schemaNode.getQName().getLocalName()); addCodegenInformation(newType, module, schemaNode); newType.setSchemaPath(schemaNode.getPath()); @@ -1710,30 +1725,18 @@ abstract class AbstractTypeGenerator { /** * Creates the name of the getter method name from localName. * - * @param localName - * string with the name of the getter method - * @param returnType - * return type - * @return string with the name of the getter method for - * methodName in JAVA method format + * @param localName string with the name of the getter method + * @param returnType return type + * @return string with the name of the getter method for methodName in JAVA method format */ public static String getterMethodName(final String localName, final Type returnType) { - final StringBuilder method = new StringBuilder(); - if (BOOLEAN.equals(returnType)) { - method.append("is"); - } else { - method.append("get"); - } - final String name = BindingMapping.toFirstUpper(BindingMapping.getPropertyName(localName)); - method.append(name); - return method.toString(); + return BindingMapping.getGetterMethodName(localName, BOOLEAN.equals(returnType)); } /** - * Created a method signature builder as part of interfaceBuilder. - * - * The method signature builder is created for the getter method of schemaNodeName. - * Also comment and returnType information are added to the builder. + * Created a method signature builder as part of interfaceBuilder. The method signature builder is + * created for the getter method of schemaNodeName. Also comment + * and returnType information are added to the builder. * * @param interfaceBuilder generated type builder for which the getter method should be created * @param returnType type which represents the return type of the getter method @@ -1748,32 +1751,31 @@ abstract class AbstractTypeGenerator { getterMethodName(node.getQName().getLocalName(), returnType)); getMethod.setReturnType(returnType); - if (node.getStatus() == Status.DEPRECATED) { - getMethod.addAnnotation("java.lang", "Deprecated"); - } + annotateDeprecatedIfNecessary(node, getMethod); addComment(getMethod, node); return getMethod; } + private static void constructNonnull(final GeneratedTypeBuilder interfaceBuilder, final Type returnType, + final ListSchemaNode node) { + final MethodSignatureBuilder getMethod = interfaceBuilder.addMethod( + BindingMapping.getNonnullMethodName(node.getQName().getLocalName())); + getMethod.setReturnType(returnType).setDefault(true); + annotateDeprecatedIfNecessary(node, getMethod); + } + /** - * Adds schemaNode to typeBuilder as getter method - * or to genTOBuilder as property. + * Adds schemaNode to typeBuilder as getter method or to genTOBuilder + * as a property. * - * @param basePackageName - * string contains the module package name - * @param schemaNode - * data schema node which should be added as getter method to - * typeBuilder or as a property to - * genTOBuilder if is part of the list key - * @param typeBuilder - * generated type builder for the list schema node - * @param genTOBuilder - * generated TO builder for the list keys - * @param listKeys - * list of string which contains names of the list keys - * @param module - * current module + * @param basePackageName string contains the module package name + * @param schemaNode data schema node which should be added as getter method to typeBuilder + * or as a property to genTOBuilder if is part of the list key + * @param typeBuilder generated type builder for the list schema node + * @param genTOBuilder generated TO builder for the list keys + * @param listKeys list of string which contains names of the list keys + * @param module current module * @throws IllegalArgumentException *
        *
      • if schemaNode equals null
      • @@ -1782,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); @@ -1799,13 +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, typeBuilder, (ContainerSchemaNode) schemaNode); + containerToGenType(context, typeBuilder, childOf(typeBuilder), + (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, typeBuilder, (ListSchemaNode) schemaNode); + listToGenType(context, typeBuilder, childOf(typeBuilder), (ListSchemaNode) schemaNode, inGrouping); } } } @@ -1816,163 +1819,108 @@ abstract class AbstractTypeGenerator { if (genTOBuilder != null) { final GeneratedTransferObject genTO = genTOBuilder.build(); - - // Fake the 'getKey()' for items, this is equivalent to constructGetter() - final MethodSignatureBuilder getMethod = typeBuilder.addMethod(getterMethodName("key", genTO)); - getMethod.setReturnType(genTO); - getMethod.setComment("Returns Primary Key of Yang List Type"); + // Add Identifiable.getKey() for items + typeBuilder.addMethod(BindingMapping.IDENTIFIABLE_KEY_NAME).setReturnType(genTO) + .addAnnotation(OVERRIDE_ANNOTATION); context.addGeneratedTOBuilder(genTOBuilder); } } /** - * Selects the names of the list keys from list and returns - * them as the list of the strings + * Selects the names of the list keys from list and returns them as the list of the strings. * - * @param list - * of string with names of the list keys - * @return list of string which represents names of the list keys. If the - * list contains no keys then the empty list is - * returned. + * @param list of string with names of the list keys + * @return list of string which represents names of the list keys. If the list contains no keys then + * 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; } /** - * Builds a GeneratedTOBuilder for a UnionType {@link UnionTypeDefinition}. - * - * If more then one generated TO builder is created for enclosing then all - * of the generated TO builders are added to typeBuilder as + * Builds a GeneratedTOBuilder for a UnionType {@link UnionTypeDefinition}. If more then one generated TO builder + * is created for enclosing then all of the generated TO builders are added to typeBuilder as * enclosing transfer objects. * - * @param typeDef - * type definition which can be of type UnionType or - * BitsTypeDefinition - * @param typeBuilder - * generated type builder to which is added generated TO created - * from typeDef - * @param leaf - * string with name for generated TO builder - * @param parentModule - * parent module + * @param typeDef type definition which can be of type UnionType or BitsTypeDefinition + * @param typeBuilder generated type builder to which is added generated TO created from typeDef + * @param leaf string with name for generated TO builder + * @param parentModule parent module * @return generated TO builder for typeDef */ - private GeneratedTOBuilder addTOToTypeBuilder(final UnionTypeDefinition typeDef, + 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); final GeneratedTOBuilder resultTOBuilder = types.remove(0); - for (final GeneratedTOBuilder genTOBuilder : types) { - resultTOBuilder.addEnclosingTransferObject(genTOBuilder); + types.forEach(resultTOBuilder::addEnclosingTransferObject); + genTOBuilders.forEach(typeBuilder::addEnclosingTransferObject); + + for (GeneratedTOBuilder builder : types) { + if (builder.isUnion()) { + final GeneratedTransferObject type = builder.build(); + createUnionBuilder(builder, typeBuilder, type, parentModule); + } } - final GeneratedPropertyBuilder genPropBuilder = resultTOBuilder.addProperty("value"); - genPropBuilder.setReturnType(Types.CHAR_ARRAY); - resultTOBuilder.addEqualsIdentity(genPropBuilder); - resultTOBuilder.addHashIdentity(genPropBuilder); - resultTOBuilder.addToStringProperty(genPropBuilder); - processEnclosedTOBuilderes(typeBuilder, genTOBuilders); - return resultTOBuilder; + return createReturnTypeForUnion(resultTOBuilder, typeDef, typeBuilder, parentModule); } /** - * Builds generated TO builders for typeDef of type {@link BitsTypeDefinition} which are - * also added to typeBuilder as enclosing transfer object. - * - * If more then one generated TO builder is created for enclosing then all - * of the generated TO builders are added to typeBuilder as - * enclosing transfer objects. + * Builds generated TO builders for typeDef of type {@link BitsTypeDefinition} which are also added + * to typeBuilder as enclosing transfer object. If more then one generated TO builder is created + * for enclosing then all of the generated TO builders are added to typeBuilder as enclosing transfer + * objects. * - * @param typeDef - * type definition which can be of type UnionType or - * BitsTypeDefinition - * @param typeBuilder - * generated type builder to which is added generated TO created - * from typeDef - * @param leaf - * string with name for generated TO builder - * @param parentModule - * parent module + * @param typeDef type definition which can be of type UnionType or BitsTypeDefinition + * @param typeBuilder generated type builder to which is added generated TO created from typeDef + * @param leaf string with name for generated TO builder + * @param parentModule parent module * @return generated TO builder for typeDef */ 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; - - } - - private static GeneratedTOBuilder processEnclosedTOBuilderes(final GeneratedTypeBuilder typeBuilder, - final List genTOBuilders) { - for (final GeneratedTOBuilder genTOBuilder : genTOBuilders) { - typeBuilder.addEnclosingTransferObject(genTOBuilder); - } - return genTOBuilders.get(0); } /** - * Adds the implemented types to type builder. - * - * The method passes through the list of uses in - * {@code dataNodeContainer}. For every use is obtained corresponding - * generated type from {@link ModuleContext#groupings - * allGroupings} which is added as implements type to - * builder + * Adds the implemented types to type builder. The method passes through the list of uses in + * {@code dataNodeContainer}. For every use is obtained corresponding generated type + * from {@link ModuleContext#groupings allGroupings} which is added as implements type + * to builder * - * @param dataNodeContainer - * element which contains the list of used YANG groupings - * @param builder - * builder to which are added implemented types according to - * dataNodeContainer + * @param dataNodeContainer element which contains the list of used YANG groupings + * @param builder builder to which are added implemented types according to dataNodeContainer * @return generated type builder with all implemented types */ private 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; } @@ -2007,9 +1955,42 @@ abstract class AbstractTypeGenerator { return null; } - private static void annotateDeprecatedIfNecessary(final Status status, final GeneratedTypeBuilder builder) { - if (status == Status.DEPRECATED) { - builder.addAnnotation("java.lang", "Deprecated"); + 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; + } }