2 * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.mdsal.binding.javav2.generator.impl;
11 import static com.google.common.base.Preconditions.checkArgument;
12 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.addTOToTypeBuilder;
13 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.annotateDeprecatedIfNecessary;
14 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.augGenTypeName;
15 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.constructGetter;
16 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createDescription;
17 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createReturnTypeForUnion;
18 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.getAugmentIdentifier;
19 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.isInnerType;
20 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.qNameConstant;
21 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveInnerEnumFromTypeDefinition;
22 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveListKeyTOBuilder;
23 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.computeDefaultSUID;
24 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.encodeAngleBrackets;
25 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.packageNameForGeneratedType;
26 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.NOTIFICATION;
27 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.parameterizedTypeFor;
28 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
30 import com.google.common.annotations.Beta;
31 import com.google.common.base.Preconditions;
32 import java.util.Collection;
33 import java.util.HashMap;
34 import java.util.List;
37 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
38 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
39 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
40 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
41 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
42 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
43 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
44 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
45 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
46 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.GroupingDefinitionDependencySort;
47 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
48 import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier;
49 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
50 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
51 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
52 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
53 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.EnumBuilder;
54 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedPropertyBuilder;
55 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder;
56 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
57 import org.opendaylight.mdsal.binding.javav2.spec.base.BaseIdentity;
58 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
59 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
60 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentable;
61 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
62 import org.opendaylight.yangtools.yang.common.QName;
63 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
64 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
65 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
66 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
67 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
68 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
69 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
70 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
71 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
72 import org.opendaylight.yangtools.yang.model.api.Module;
73 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
74 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
75 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
76 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
77 import org.opendaylight.yangtools.yang.model.api.Status;
78 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
79 import org.opendaylight.yangtools.yang.model.api.UsesNode;
80 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
81 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
82 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
83 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
86 * Helper util class used for generation of types in Binding spec v2.
89 final class GenHelperUtil {
91 private GenHelperUtil() {
92 throw new UnsupportedOperationException("Util class");
96 * Create GeneratedTypeBuilder object from module argument.
99 * Module object from which builder will be created
101 * @param verboseClassComments
103 * @return <code>GeneratedTypeBuilder</code> which is internal
104 * representation of the module
105 * @throws IllegalArgumentException
108 static GeneratedTypeBuilder moduleToDataType(final Module module, final Map<Module, ModuleContext> genCtx, final boolean verboseClassComments) {
109 Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
111 final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data", verboseClassComments);
112 addImplementedInterfaceFromUses(module, moduleDataTypeBuilder, genCtx);
113 moduleDataTypeBuilder.addImplementsType(BindingTypes.TREE_ROOT);
114 moduleDataTypeBuilder.addComment(module.getDescription());
115 moduleDataTypeBuilder.setDescription(createDescription(module, verboseClassComments));
116 moduleDataTypeBuilder.setReference(module.getReference());
117 return moduleDataTypeBuilder;
121 * Generates type builder for <code>module</code>.
124 * Module which is source of package name for generated type
127 * string which is added to the module class name representation
129 * @param verboseClassComments
130 * @return instance of GeneratedTypeBuilder which represents
131 * <code>module</code>.
132 * @throws IllegalArgumentException
133 * if <code>module</code> is null
135 static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean
136 verboseClassComments) {
137 Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
138 final String packageName = BindingMapping.getRootPackageName(module);
139 // underscore used as separator for distinction of module name parts
140 final String moduleName = new StringBuilder(module.getName()).append('_').append(postfix).toString();
142 final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
143 moduleBuilder.setDescription(createDescription(module, verboseClassComments));
144 moduleBuilder.setReference(module.getReference());
145 moduleBuilder.setModuleName(moduleName);
147 return moduleBuilder;
151 * Adds the implemented types to type builder.
153 * The method passes through the list of <i>uses</i> in
154 * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding
155 * generated type from all groupings
156 * allGroupings} which is added as <i>implements type</i> to
157 * <code>builder</code>
159 * @param dataNodeContainer
160 * element which contains the list of used YANG groupings
162 * builder to which are added implemented types according to
163 * <code>dataNodeContainer</code>
164 * @param genCtx generated context
165 * @return generated type builder with all implemented types
167 static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
168 final GeneratedTypeBuilder builder, final Map<Module, ModuleContext> genCtx) {
169 for (final UsesNode usesNode : dataNodeContainer.getUses()) {
170 final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath(), genCtx).toInstance();
171 if (genType == null) {
172 throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
173 + builder.getName());
175 builder.addImplementsType(genType);
180 static GeneratedTypeBuilder findGroupingByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
181 for (final ModuleContext ctx : genCtx.values()) {
182 final GeneratedTypeBuilder result = ctx.getGrouping(path);
183 if (result != null) {
191 * Adds the methods to <code>typeBuilder</code> which represent subnodes of
192 * node for which <code>typeBuilder</code> was created.
194 * The subnodes aren't mapped to the methods if they are part of grouping or
195 * augment (in this case are already part of them).
199 * @param basePackageName
200 * string contains the module package name
202 * generated type builder which represents any node. The subnodes
203 * of this node are added to the <code>typeBuilder</code> as
204 * methods. The subnode can be of type leaf, leaf-list, list,
209 * set of data schema nodes which are the children of the node
210 * for which <code>typeBuilder</code> was created
211 * @return generated type builder which is the same builder as input
212 * parameter. The getter methods (representing child nodes) could be
215 static GeneratedTypeBuilder resolveDataSchemaNodes(final Module module, final String basePackageName,
216 final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf,
217 final Iterable<DataSchemaNode> schemaNodes, final Map<Module, ModuleContext> genCtx,
218 final SchemaContext schemaContext, final boolean verboseClassComments,
219 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
220 final TypeProvider typeProvider) {
222 if (schemaNodes != null && parent != null) {
223 for (final DataSchemaNode schemaNode : schemaNodes) {
224 if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) {
225 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module, genCtx,
226 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
233 static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
234 schemaNode, final Module module, final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext,
235 final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
236 final TypeProvider typeProvider) {
237 return addDefaultInterfaceDefinition(packageName, schemaNode, null, module, genCtx, schemaContext,
238 verboseClassComments, genTypeBuilders, typeProvider);
241 static Map<Module, ModuleContext> processUsesAugments(final SchemaContext schemaContext, final
242 DataNodeContainer node, final Module module, Map<Module, ModuleContext> genCtx,
243 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
244 final boolean verboseClassComments, final TypeProvider typeProvider) {
245 final String basePackageName = BindingMapping.getRootPackageName(module);
246 for (final UsesNode usesNode : node.getUses()) {
247 for (final AugmentationSchema augment : usesNode.getAugmentations()) {
248 genCtx = AugmentToGenType.usesAugmentationToGenTypes(schemaContext, basePackageName, augment, module,
249 usesNode, node, genCtx, genTypeBuilders, verboseClassComments, typeProvider);
250 genCtx = processUsesAugments(schemaContext, augment, module, genCtx, genTypeBuilders,
251 verboseClassComments, typeProvider);
257 static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
258 for (final ModuleContext ctx : genCtx.values()) {
259 final GeneratedTypeBuilder result = ctx.getChildNode(path);
260 if (result != null) {
267 static GeneratedTypeBuilder findCaseByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
268 for (final ModuleContext ctx : genCtx.values()) {
269 final GeneratedTypeBuilder result = ctx.getCase(path);
270 if (result != null) {
278 * Returns a generated type builder for an augmentation.
280 * The name of the type builder is equal to the name of augmented node with
281 * serial number as suffix.
285 * @param augmentPackageName
286 * string with contains the package name to which the augment
288 * @param basePackageName
289 * string with the package name to which the augmented node
291 * @param targetTypeRef
294 * augmentation schema which contains data about the child nodes
295 * and uses of augment
296 * @return generated type builder for augment in genCtx
298 static Map<Module, ModuleContext> addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
299 final String basePackageName, final Type targetTypeRef, final AugmentationSchema augSchema,
300 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module,
301 ModuleContext> genCtx, final SchemaContext schemaContext, final boolean verboseClassComments, final
302 TypeProvider typeProvider) {
304 Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.computeIfAbsent(augmentPackageName, k -> new HashMap<>());
305 String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes());
307 if (augIdentifier == null) {
308 augIdentifier = augGenTypeName(augmentBuilders, targetTypeRef.getName());
311 GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augIdentifier);
313 augTypeBuilder.addImplementsType(BindingTypes.TREE_NODE);
314 augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
315 annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
316 augTypeBuilder = addImplementedInterfaceFromUses(augSchema, augTypeBuilder, genCtx);
318 augTypeBuilder = augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema
319 .getChildNodes(), genCtx, schemaContext, verboseClassComments, typeProvider, genTypeBuilders);
320 augmentBuilders.put(augTypeBuilder.getName(), augTypeBuilder);
322 if(!augSchema.getChildNodes().isEmpty()) {
323 genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema);
326 genCtx.get(module).addAugmentType(augTypeBuilder);
331 * Adds the methods to <code>typeBuilder</code> what represents subnodes of
332 * node for which <code>typeBuilder</code> was created.
336 * @param basePackageName
337 * string contains the module package name
339 * generated type builder which represents any node. The subnodes
340 * of this node are added to the <code>typeBuilder</code> as
341 * methods. The subnode can be of type leaf, leaf-list, list,
346 * set of data schema nodes which are the children of the node
347 * for which <code>typeBuilder</code> was created
348 * @return generated type builder which is the same object as the input
349 * parameter <code>typeBuilder</code>. The getter method could be
352 private static GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
353 final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Iterable<DataSchemaNode> schemaNodes,
354 final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
355 verboseClassComments, final TypeProvider typeProvider, final Map<String, Map<String,
356 GeneratedTypeBuilder>> genTypeBuilders) {
357 if (schemaNodes != null && typeBuilder != null) {
358 for (final DataSchemaNode schemaNode : schemaNodes) {
359 if (!schemaNode.isAugmenting()) {
360 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module, genCtx,
361 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
369 * Instantiates generated type builder with <code>packageName</code> and
370 * <code>schemaNode</code>.
372 * The new builder always implements
373 * {@link TreeNode TreeNode}.<br>
374 * If <code>schemaNode</code> is instance of GroupingDefinition it also
375 * implements {@link Augmentable
377 * If <code>schemaNode</code> is instance of
378 * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
379 * DataNodeContainer} it can also implement nodes which are specified in
383 * string with the name of the package to which
384 * <code>schemaNode</code> belongs.
386 * schema node for which is created generated type builder
388 * parent type (can be null)
389 * @param schemaContext schema context
390 * @return generated type builder <code>schemaNode</code>
392 static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
393 schemaNode, final Type parent, final Module module, final Map<Module, ModuleContext> genCtx,
394 final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String,
395 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
397 GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, schemaContext, "",
398 verboseClassComments, genTypeBuilders);
399 if (parent == null) {
400 it.addImplementsType(BindingTypes.TREE_NODE);
402 if (parent instanceof ListSchemaNode) {
403 it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
404 (BindingTypes.IDENTIFIABLE_ITEM, parent)));
406 it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
407 (BindingTypes.ITEM, parent)));
408 it.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, it));
412 if (!(schemaNode instanceof GroupingDefinition)) {
413 it.addImplementsType(BindingTypes.augmentable(it));
416 if (schemaNode instanceof DataNodeContainer) {
417 groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings(), genCtx, schemaContext,
418 verboseClassComments, genTypeBuilders, typeProvider);
419 it = addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it, genCtx);
425 static GeneratedTypeBuilder resolveNotification(final GeneratedTypeBuilder listenerInterface, String
426 parentName, final String basePackageName, final NotificationDefinition notification, final Module module,
427 final SchemaContext schemaContext, final boolean verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>>
428 genTypeBuilders, TypeProvider typeProvider, Map<Module, ModuleContext> genCtx) {
430 processUsesAugments(schemaContext, notification, module, genCtx, genTypeBuilders,
431 verboseClassComments, typeProvider);
433 final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition
434 (basePackageName, notification, null, module, genCtx, schemaContext,
435 verboseClassComments, genTypeBuilders, typeProvider);
436 annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
437 notificationInterface.addImplementsType(NOTIFICATION);
438 genCtx.get(module).addChildNodeType(notification, notificationInterface);
440 // Notification object
441 resolveDataSchemaNodes(module, basePackageName, notificationInterface,
442 notificationInterface, notification.getChildNodes(), genCtx, schemaContext,
443 verboseClassComments, genTypeBuilders, typeProvider);
445 //in case of tied notification, incorporate parent's localName
446 final StringBuilder sb = new StringBuilder("on_");
447 if (parentName != null) {
448 sb.append(parentName).append('_');
450 sb.append(notificationInterface.getName());
452 listenerInterface.addMethod(JavaIdentifierNormalizer.normalizeSpecificIdentifier(sb.toString(), JavaIdentifier.METHOD))
453 .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
454 .setComment(encodeAngleBrackets(notification.getDescription())).setReturnType(Types.VOID);
455 return listenerInterface;
459 * Returns reference to generated type builder for specified
460 * <code>schemaNode</code> with <code>packageName</code>.
462 * Firstly the generated type builder is searched in
463 * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
464 * found it is created and added to <code>genTypeBuilders</code>.
467 * string with the package name to which returning generated type
470 * schema node which provide data about the schema node name
471 * @param schemaContext schema context
473 * return type name prefix
474 * @return generated type builder for <code>schemaNode</code>
475 * @throws IllegalArgumentException
477 * <li>if <code>schemaNode</code> is null</li>
478 * <li>if <code>packageName</code> is null</li>
479 * <li>if QName of schema node is null</li>
480 * <li>if schemaNode name is null</li>
484 static GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
485 final SchemaContext schemaContext, final String prefix, final boolean verboseClassComments,
486 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
488 Preconditions.checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
489 Preconditions.checkArgument(packageName != null, "Package Name for Generated Type cannot be NULL.");
490 String schemaNodeName = schemaNode.getQName().getLocalName();
491 Preconditions.checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL.");
493 if (prefix != null && !prefix.isEmpty()) {
494 // underscore used as separator for distinction of class name parts
495 schemaNodeName = new StringBuilder(prefix).append('_').append(schemaNodeName).toString();
498 final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, schemaNodeName);
499 final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode);
500 qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
501 newType.addComment(schemaNode.getDescription());
502 newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName(), schemaContext, verboseClassComments));
503 newType.setReference(schemaNode.getReference());
504 newType.setSchemaPath((List<QName>) schemaNode.getPath().getPathFromRoot());
505 newType.setModuleName(module.getName());
507 if (!genTypeBuilders.containsKey(packageName)) {
508 final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
509 builders.put(newType.getName(), newType);
510 genTypeBuilders.put(packageName, builders);
512 final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
513 if (!builders.containsKey(newType.getName())) {
514 builders.put(newType.getName(), newType);
521 private static void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode node,
522 final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Module module,
523 final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean verboseClassComments,
524 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
525 //TODO: implement rest of schema nodes GTO building
526 if (node != null && typeBuilder != null) {
527 if (node instanceof ContainerSchemaNode) {
528 containerToGenType(module, basePackageName, typeBuilder, childOf, (ContainerSchemaNode) node,
529 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
530 } else if (node instanceof LeafSchemaNode) {
531 resolveLeafSchemaNodeAsMethod(schemaContext, typeBuilder, genCtx, (LeafSchemaNode) node, module,
533 } else if (node instanceof ListSchemaNode) {
534 listToGenType(module, basePackageName, typeBuilder, childOf, (ListSchemaNode) node, schemaContext,
535 verboseClassComments, genCtx, genTypeBuilders, typeProvider);
536 } else if (node instanceof AnyXmlSchemaNode) {
537 resolveAnyxmlNodeAsMethod(schemaContext, typeBuilder, genCtx, (AnyXmlSchemaNode) node, module,
544 private static void containerToGenType(final Module module, final String basePackageName,
545 final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node,
546 final SchemaContext schemaContext, final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
547 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
549 final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
550 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
551 if (genType != null) {
552 constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), genType, node.getStatus());
553 resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes(), genCtx,
554 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
558 private static void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder
559 parent, final GeneratedTypeBuilder childOf, final ListSchemaNode node, final SchemaContext schemaContext,
560 final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
561 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
562 final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
563 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
564 if (genType != null) {
565 final String nodeName = node.getQName().getLocalName();
566 constructGetter(parent, nodeName, node.getDescription(),
567 Types.listTypeFor(genType), node.getStatus());
568 final List<QName> listKeys = node.getKeyDefinition();
569 final String packageName = new StringBuilder(packageNameForGeneratedType(basePackageName, node.getPath(),
570 BindingNamespaceType.Key)).append('.').append(nodeName).toString();
572 final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node);
574 for (final DataSchemaNode schemaNode : node.getChildNodes()) {
575 if (!schemaNode.isAugmenting()) {
576 addSchemaNodeToListBuilders(nodeName, basePackageName, schemaNode, genType, genTOBuilder, listKeys,
577 module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments);
582 if (genTOBuilder != null) {
583 final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
584 prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder)));
585 genTOBuilder.setSUID(prop);
588 typeBuildersToGenTypes(module, genType, genTOBuilder, genCtx);
592 private static void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
593 final GeneratedTOBuilder genTOBuilder, final Map<Module, ModuleContext> genCtx) {
594 checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
595 if (genTOBuilder != null) {
596 final GeneratedTransferObject genTO = genTOBuilder.toInstance();
597 constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO, Status.CURRENT);
598 genCtx.get(module).addGeneratedTOBuilder(genTOBuilder);
603 * Converts <code>leaf</code> to the getter method which is added to
604 * <code>typeBuilder</code>.
607 * generated type builder to which is added getter method as
608 * <code>leaf</code> mapping
610 * leaf schema node which is mapped as getter method which is
611 * added to <code>typeBuilder</code>
613 * Module in which type was defined
614 * @return boolean value
616 * <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
618 * <li>true - in other cases</li>
621 private static Type resolveLeafSchemaNodeAsMethod(final SchemaContext schemaContext, final GeneratedTypeBuilder
622 typeBuilder, final Map<Module, ModuleContext> genCtx, final LeafSchemaNode leaf, final Module module,
623 final TypeProvider typeProvider) {
624 if (leaf == null || typeBuilder == null || leaf.isAddedByUses()) {
628 final String leafName = leaf.getQName().getLocalName();
629 if (leafName == null) {
633 final Module parentModule = findParentModule(schemaContext, leaf);
634 Type returnType = null;
636 final TypeDefinition<?> typeDef = leaf.getType();
637 if (isInnerType(leaf, typeDef)) {
638 if (typeDef instanceof EnumTypeDefinition) {
639 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
640 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
641 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(),
642 genCtx, typeBuilder, module);
643 if (enumBuilder != null) {
644 returnType = enumBuilder.toInstance(typeBuilder);
646 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
647 } else if (typeDef instanceof UnionTypeDefinition) {
648 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
649 typeProvider, schemaContext);
650 if (genTOBuilder != null) {
651 //TODO: https://bugs.opendaylight.org/show_bug.cgi?id=2289
652 returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule, typeProvider);
654 } else if (typeDef instanceof BitsTypeDefinition) {
655 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
656 typeProvider, schemaContext);
657 if (genTOBuilder != null) {
658 returnType = genTOBuilder.toInstance();
661 // It is constrained version of already declared type (inner declared type exists,
662 // onlyfor special cases (Enum, Union, Bits), which were already checked.
663 // In order to get proper class we need to look up closest derived type
664 // and apply restrictions from leaf type
665 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
666 returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
670 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
671 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
674 if (returnType == null) {
678 if (typeDef instanceof EnumTypeDefinition) {
679 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
682 String leafDesc = leaf.getDescription();
683 if (leafDesc == null) {
687 constructGetter(typeBuilder, leafName, leafDesc, returnType, leaf.getStatus());
691 private static Type resolveAnyxmlNodeAsMethod(final SchemaContext schemaContext, final GeneratedTypeBuilder
692 typeBuilder, final Map<Module, ModuleContext> genCtx, final AnyXmlSchemaNode anyxml, final Module module,
693 final TypeProvider typeProvider) {
695 final String anyxmlName = anyxml.getQName().getLocalName();
696 if (anyxmlName == null) {
700 String anyxmlDesc = anyxml.getDescription();
701 if (anyxmlDesc == null) {
705 Type returnType = Types.DOCUMENT;
707 constructGetter(typeBuilder, anyxmlName, anyxmlDesc, returnType, anyxml.getStatus());
713 * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
714 * or to <code>genTOBuilder</code> as property.
717 * string contains the name of list
718 * @param basePackageName
719 * string contains the module package name
721 * data schema node which should be added as getter method to
722 * <code>typeBuilder</code> or as a property to
723 * <code>genTOBuilder</code> if is part of the list key
725 * generated type builder for the list schema node
726 * @param genTOBuilder
727 * generated TO builder for the list keys
729 * list of string which contains QNames of the list keys
732 * @param typeProvider
733 * provider that defines contract for generated types
734 * @param schemaContext
737 * map of generated entities in context of YANG modules
738 * @param genTypeBuilders
739 * map of generated type builders
740 * @param verboseClassComments
741 * generate verbose comments
742 * @throws IllegalArgumentException
744 * <li>if <code>schemaNode</code> equals null</li>
745 * <li>if <code>typeBuilder</code> equals null</li>
748 private static void addSchemaNodeToListBuilders(final String nodeName, final String basePackageName,
749 final DataSchemaNode schemaNode, final GeneratedTypeBuilder typeBuilder,
750 final GeneratedTOBuilder genTOBuilder, final List<QName> listKeys, final Module module,
751 final TypeProvider typeProvider, final SchemaContext schemaContext, final Map<Module, ModuleContext> genCtx,
752 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final boolean verboseClassComments) {
753 checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
754 checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
756 if (schemaNode instanceof LeafSchemaNode) {
757 final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
758 final QName leafQName = leaf.getQName();
759 final String leafName = leafQName.getLocalName();
760 String leafPckgName = basePackageName;
761 boolean isKeyPart = false;
762 if (listKeys.contains(leafQName)) {
763 leafPckgName = new StringBuilder(leafPckgName).append('.').append(BindingNamespaceType.Key).append('.')
764 .append(nodeName).toString();
767 leafPckgName = new StringBuilder(leafPckgName).append('.').append(BindingNamespaceType.Data).append('.')
768 .append(nodeName).toString();
771 final String leafGTOName = new StringBuilder(nodeName).append('_').append(leafName).toString();
772 final GeneratedTypeBuilder leafGTp = new GeneratedTypeBuilderImpl(leafPckgName, leafGTOName);
773 resolveLeafSchemaNodeAsMethod(schemaContext, leafGTp, genCtx, leaf, module,
776 constructGetter(typeBuilder, leafGTOName, schemaNode.getDescription(), leafGTp, Status.CURRENT);
779 AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, leafGTp, true);
781 } else if (!schemaNode.isAddedByUses()) {
782 //TODO: implement leaf list to generated type
783 //TODO: implement choice to generated type
784 if (schemaNode instanceof ContainerSchemaNode) {
785 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode,
786 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
787 } else if (schemaNode instanceof ListSchemaNode) {
788 listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode,
789 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
794 private static TypeDefinition<?> getBaseOrDeclaredType(final TypeDefinition<?> typeDef) {
795 final TypeDefinition<?> baseType = typeDef.getBaseType();
796 return (baseType != null && baseType.getBaseType() != null) ? baseType : typeDef;
799 @SuppressWarnings({ "rawtypes", "unchecked" })
800 private static GeneratedTypeBuilder processDataSchemaNode(final Module module, final String basePackageName,
801 final GeneratedTypeBuilder childOf, final DataSchemaNode node, final SchemaContext schemaContext,
802 final boolean verboseClassComments, Map<Module, ModuleContext> genCtx, final Map<String, Map<String,
803 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
805 if (node.isAugmenting() || node.isAddedByUses()) {
808 final String packageName = packageNameForGeneratedType(basePackageName, node.getPath(), BindingNamespaceType.Data);
809 final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf, module,
810 genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
811 genType.addComment(node.getDescription());
812 annotateDeprecatedIfNecessary(node.getStatus(), genType);
813 genType.setDescription(createDescription(node, genType.getFullyQualifiedName(), schemaContext, verboseClassComments));
814 genType.setModuleName(module.getName());
815 genType.setReference(node.getReference());
816 genType.setSchemaPath((List) node.getPath().getPathFromRoot());
817 genType.setParentTypeForBuilder(childOf);
818 if (node instanceof DataNodeContainer) {
819 genCtx.get(module).addChildNodeType(node, genType);
820 genCtx = groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings(), genCtx, schemaContext,
821 verboseClassComments, genTypeBuilders, typeProvider);
822 processUsesAugments(schemaContext, (DataNodeContainer) node, module, genCtx, genTypeBuilders,
823 verboseClassComments, typeProvider);
829 * Converts all <b>groupings</b> of the module to the list of
830 * <code>Type</code> objects. Firstly are groupings sorted according mutual
831 * dependencies. At least dependent (independent) groupings are in the list
832 * saved at first positions. For every grouping the record is added to map
833 * {@link ModuleContext#groupings allGroupings}
838 * collection of groupings from which types will be generated
839 * @param typeProvider
840 * provider that defines contract for generated types
841 * @param schemaContext
844 * map of generated entities in context of YANG modules
845 * @param genTypeBuilders
846 * map of generated type builders
847 * @param verboseClassComments
848 * generate verbose comments
851 static Map<Module, ModuleContext> groupingsToGenTypes(final Module module, final Collection<GroupingDefinition>
852 groupings, Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
853 verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
854 final String basePackageName = BindingMapping.getRootPackageName(module);
855 final List<GroupingDefinition> groupingsSortedByDependencies = new GroupingDefinitionDependencySort()
857 for (final GroupingDefinition grouping : groupingsSortedByDependencies) {
858 genCtx = groupingToGenType(basePackageName, grouping, module, genCtx, schemaContext,
859 verboseClassComments, genTypeBuilders, typeProvider);
865 * Converts individual grouping to GeneratedType. Firstly generated type
866 * builder is created and every child node of grouping is resolved to the
869 * @param basePackageName
870 * string contains the module package name
872 * GroupingDefinition which contains data about grouping
875 * @param typeProvider
876 * provider that defines contract for generated types
877 * @param schemaContext
880 * map of generated entities in context of YANG modules
881 * @param genTypeBuilders
882 * map of generated type builders
883 * @param verboseClassComments
884 * generate verbose comments
886 * @return GeneratedType which is generated from grouping (object of type
887 * <code>GroupingDefinition</code>)
889 private static Map<Module, ModuleContext> groupingToGenType(final String basePackageName, final GroupingDefinition grouping, final Module
890 module, Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
891 verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
892 final String packageName = packageNameForGeneratedType(basePackageName, grouping.getPath(), BindingNamespaceType.Grouping);
893 final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, grouping, module, genCtx,
894 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
895 annotateDeprecatedIfNecessary(grouping.getStatus(), genType);
896 genCtx.get(module).addGroupingType(grouping.getPath(), genType);
897 resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes(), genCtx,
898 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
899 genCtx = groupingsToGenTypes(module, grouping.getGroupings(), genCtx, schemaContext, verboseClassComments,
900 genTypeBuilders, typeProvider);
901 genCtx = processUsesAugments(schemaContext, grouping, module, genCtx, genTypeBuilders, verboseClassComments,
907 * //TODO: add information about multiple base identities in YANG 1.1
908 * Converts the <b>identity</b> object to GeneratedType. Firstly it is
909 * created transport object builder. If identity contains base identity then
910 * reference to base identity is added to superior identity as its extend.
911 * If identity doesn't contain base identity then only reference to abstract
912 * class {@link org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
913 * BaseIdentity} is added
917 * @param basePackageName
918 * string contains the module package name
920 * IdentitySchemaNode which contains data about identity
921 * @param schemaContext
922 * SchemaContext which is used to get package and name
923 * information about base of identity
924 * @param genCtx generated context
925 * @return returns generated context
927 static Map<Module, ModuleContext> identityToGenType(final Module module, final String basePackageName,
928 final IdentitySchemaNode identity, final SchemaContext schemaContext, Map<Module, ModuleContext> genCtx,
929 boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
930 final TypeProvider typeProvider, Map<QName, GeneratedTOBuilderImpl> generatedIdentities) {
932 final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, identity.getPath(),
933 BindingNamespaceType.Identity);
934 final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName,
935 identity.getQName().getLocalName());
937 final Set<IdentitySchemaNode> baseIdentities = identity.getBaseIdentities();
938 if (baseIdentities.size() == 0) {
940 final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(BaseIdentity.class.getPackage().getName(),
941 BaseIdentity.class.getSimpleName());
942 newType.setExtendsType(gto.toInstance());
943 generatedIdentities.put(identity.getQName(), newType);
945 //one base - inheritance
946 final IdentitySchemaNode baseIdentity = baseIdentities.iterator().next();
947 final Module baseIdentityParentModule = SchemaContextUtil.findParentModule(schemaContext, baseIdentity);
948 final String returnTypePkgName = new StringBuilder(BindingMapping.getRootPackageName
949 (baseIdentityParentModule))
951 .append(BindingNamespaceType.Identity.getPackagePrefix())
954 final GeneratedTOBuilderImpl existingIdentityGto = generatedIdentities.get(baseIdentity.getQName());
955 if (existingIdentityGto != null) {
956 newType.setExtendsType(existingIdentityGto.toInstance());
958 final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(returnTypePkgName,
959 baseIdentity.getQName().getLocalName());
960 newType.setExtendsType(gto.toInstance());
961 generatedIdentities.put(baseIdentity.getQName(), gto);
964 //FIXME: more bases - possible composition, multiple inheritance not possible
966 generatedIdentities.put(identity.getQName(), newType);
968 newType.setAbstract(true);
969 newType.addComment(identity.getDescription());
970 newType.setDescription(createDescription(identity, newType.getFullyQualifiedName(), schemaContext,
971 verboseClassComments));
972 newType.setReference(identity.getReference());
973 newType.setModuleName(module.getName());
974 newType.setSchemaPath((List) identity.getPath().getPathFromRoot());
976 qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, identity.getQName());
978 genCtx.get(module).addIdentityType(identity.getQName(), newType);