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;
36 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
37 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
38 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
39 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
40 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
41 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
42 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
43 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
44 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.GroupingDefinitionDependencySort;
45 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
46 import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier;
47 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
48 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
49 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
50 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
51 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.EnumBuilder;
52 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedPropertyBuilder;
53 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder;
54 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
55 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
56 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
57 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentable;
58 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
59 import org.opendaylight.yangtools.yang.common.QName;
60 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
61 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
62 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
63 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
64 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
65 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
66 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
67 import org.opendaylight.yangtools.yang.model.api.Module;
68 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
69 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
70 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
71 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
72 import org.opendaylight.yangtools.yang.model.api.Status;
73 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
74 import org.opendaylight.yangtools.yang.model.api.UsesNode;
75 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
76 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
77 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
78 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
81 * Helper util class used for generation of types in Binding spec v2.
84 final class GenHelperUtil {
86 private GenHelperUtil() {
87 throw new UnsupportedOperationException("Util class");
91 * Create GeneratedTypeBuilder object from module argument.
94 * Module object from which builder will be created
96 * @param verboseClassComments
98 * @return <code>GeneratedTypeBuilder</code> which is internal
99 * representation of the module
100 * @throws IllegalArgumentException
103 static GeneratedTypeBuilder moduleToDataType(final Module module, final Map<Module, ModuleContext> genCtx, final boolean verboseClassComments) {
104 Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
106 final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data", verboseClassComments);
107 addImplementedInterfaceFromUses(module, moduleDataTypeBuilder, genCtx);
108 moduleDataTypeBuilder.addImplementsType(BindingTypes.TREE_ROOT);
109 moduleDataTypeBuilder.addComment(module.getDescription());
110 moduleDataTypeBuilder.setDescription(createDescription(module, verboseClassComments));
111 moduleDataTypeBuilder.setReference(module.getReference());
112 return moduleDataTypeBuilder;
116 * Generates type builder for <code>module</code>.
119 * Module which is source of package name for generated type
122 * string which is added to the module class name representation
124 * @param verboseClassComments
125 * @return instance of GeneratedTypeBuilder which represents
126 * <code>module</code>.
127 * @throws IllegalArgumentException
128 * if <code>module</code> is null
130 static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean
131 verboseClassComments) {
132 Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
133 final String packageName = BindingMapping.getRootPackageName(module);
134 // underscore used as separator for distinction of module name parts
135 final String moduleName = new StringBuilder(module.getName()).append('_').append(postfix).toString();
137 final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
138 moduleBuilder.setDescription(createDescription(module, verboseClassComments));
139 moduleBuilder.setReference(module.getReference());
140 moduleBuilder.setModuleName(moduleName);
142 return moduleBuilder;
146 * Adds the implemented types to type builder.
148 * The method passes through the list of <i>uses</i> in
149 * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding
150 * generated type from all groupings
151 * allGroupings} which is added as <i>implements type</i> to
152 * <code>builder</code>
154 * @param dataNodeContainer
155 * element which contains the list of used YANG groupings
157 * builder to which are added implemented types according to
158 * <code>dataNodeContainer</code>
159 * @param genCtx generated context
160 * @return generated type builder with all implemented types
162 static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
163 final GeneratedTypeBuilder builder, final Map<Module, ModuleContext> genCtx) {
164 for (final UsesNode usesNode : dataNodeContainer.getUses()) {
165 final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath(), genCtx).toInstance();
166 if (genType == null) {
167 throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
168 + builder.getName());
170 builder.addImplementsType(genType);
175 static GeneratedTypeBuilder findGroupingByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
176 for (final ModuleContext ctx : genCtx.values()) {
177 final GeneratedTypeBuilder result = ctx.getGrouping(path);
178 if (result != null) {
186 * Adds the methods to <code>typeBuilder</code> which represent subnodes of
187 * node for which <code>typeBuilder</code> was created.
189 * The subnodes aren't mapped to the methods if they are part of grouping or
190 * augment (in this case are already part of them).
194 * @param basePackageName
195 * string contains the module package name
197 * generated type builder which represents any node. The subnodes
198 * of this node are added to the <code>typeBuilder</code> as
199 * methods. The subnode can be of type leaf, leaf-list, list,
204 * set of data schema nodes which are the children of the node
205 * for which <code>typeBuilder</code> was created
206 * @return generated type builder which is the same builder as input
207 * parameter. The getter methods (representing child nodes) could be
210 static GeneratedTypeBuilder resolveDataSchemaNodes(final Module module, final String basePackageName,
211 final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf,
212 final Iterable<DataSchemaNode> schemaNodes, final Map<Module, ModuleContext> genCtx,
213 final SchemaContext schemaContext, final boolean verboseClassComments,
214 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
215 final TypeProvider typeProvider) {
217 if (schemaNodes != null && parent != null) {
218 for (final DataSchemaNode schemaNode : schemaNodes) {
219 if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) {
220 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module, genCtx,
221 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
228 static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
229 schemaNode, final Module module, final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext,
230 final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
231 final TypeProvider typeProvider) {
232 return addDefaultInterfaceDefinition(packageName, schemaNode, null, module, genCtx, schemaContext,
233 verboseClassComments, genTypeBuilders, typeProvider);
236 static Map<Module, ModuleContext> processUsesAugments(final SchemaContext schemaContext, final
237 DataNodeContainer node, final Module module, Map<Module, ModuleContext> genCtx,
238 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
239 final boolean verboseClassComments, final TypeProvider typeProvider) {
240 final String basePackageName = BindingMapping.getRootPackageName(module);
241 for (final UsesNode usesNode : node.getUses()) {
242 for (final AugmentationSchema augment : usesNode.getAugmentations()) {
243 genCtx = AugmentToGenType.usesAugmentationToGenTypes(schemaContext, basePackageName, augment, module,
244 usesNode, node, genCtx, genTypeBuilders, verboseClassComments, typeProvider);
245 genCtx = processUsesAugments(schemaContext, augment, module, genCtx, genTypeBuilders,
246 verboseClassComments, typeProvider);
252 static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
253 for (final ModuleContext ctx : genCtx.values()) {
254 final GeneratedTypeBuilder result = ctx.getChildNode(path);
255 if (result != null) {
262 static GeneratedTypeBuilder findCaseByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
263 for (final ModuleContext ctx : genCtx.values()) {
264 final GeneratedTypeBuilder result = ctx.getCase(path);
265 if (result != null) {
273 * Returns a generated type builder for an augmentation.
275 * The name of the type builder is equal to the name of augmented node with
276 * serial number as suffix.
280 * @param augmentPackageName
281 * string with contains the package name to which the augment
283 * @param basePackageName
284 * string with the package name to which the augmented node
286 * @param targetTypeRef
289 * augmentation schema which contains data about the child nodes
290 * and uses of augment
291 * @return generated type builder for augment in genCtx
293 static Map<Module, ModuleContext> addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
294 final String basePackageName, final Type targetTypeRef, final AugmentationSchema augSchema,
295 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module,
296 ModuleContext> genCtx, final SchemaContext schemaContext, final boolean verboseClassComments, final
297 TypeProvider typeProvider) {
299 Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.computeIfAbsent(augmentPackageName, k -> new HashMap<>());
300 String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes());
302 if (augIdentifier == null) {
303 augIdentifier = augGenTypeName(augmentBuilders, targetTypeRef.getName());
306 GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augIdentifier);
308 augTypeBuilder.addImplementsType(BindingTypes.TREE_NODE);
309 augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
310 annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
311 augTypeBuilder = addImplementedInterfaceFromUses(augSchema, augTypeBuilder, genCtx);
313 augTypeBuilder = augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema
314 .getChildNodes(), genCtx, schemaContext, verboseClassComments, typeProvider, genTypeBuilders);
315 augmentBuilders.put(augTypeBuilder.getName(), augTypeBuilder);
317 if(!augSchema.getChildNodes().isEmpty()) {
318 genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema);
321 genCtx.get(module).addAugmentType(augTypeBuilder);
326 * Adds the methods to <code>typeBuilder</code> what represents subnodes of
327 * node for which <code>typeBuilder</code> was created.
331 * @param basePackageName
332 * string contains the module package name
334 * generated type builder which represents any node. The subnodes
335 * of this node are added to the <code>typeBuilder</code> as
336 * methods. The subnode can be of type leaf, leaf-list, list,
341 * set of data schema nodes which are the children of the node
342 * for which <code>typeBuilder</code> was created
343 * @return generated type builder which is the same object as the input
344 * parameter <code>typeBuilder</code>. The getter method could be
347 private static GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
348 final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Iterable<DataSchemaNode> schemaNodes,
349 final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
350 verboseClassComments, final TypeProvider typeProvider, final Map<String, Map<String,
351 GeneratedTypeBuilder>> genTypeBuilders) {
352 if (schemaNodes != null && typeBuilder != null) {
353 for (final DataSchemaNode schemaNode : schemaNodes) {
354 if (!schemaNode.isAugmenting()) {
355 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module, genCtx,
356 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
364 * Instantiates generated type builder with <code>packageName</code> and
365 * <code>schemaNode</code>.
367 * The new builder always implements
368 * {@link TreeNode TreeNode}.<br>
369 * If <code>schemaNode</code> is instance of GroupingDefinition it also
370 * implements {@link Augmentable
372 * If <code>schemaNode</code> is instance of
373 * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
374 * DataNodeContainer} it can also implement nodes which are specified in
378 * string with the name of the package to which
379 * <code>schemaNode</code> belongs.
381 * schema node for which is created generated type builder
383 * parent type (can be null)
384 * @param schemaContext schema context
385 * @return generated type builder <code>schemaNode</code>
387 static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
388 schemaNode, final Type parent, final Module module, final Map<Module, ModuleContext> genCtx,
389 final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String,
390 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
392 GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, schemaContext, "",
393 verboseClassComments, genTypeBuilders);
394 if (parent == null) {
395 it.addImplementsType(BindingTypes.TREE_NODE);
397 if (parent instanceof ListSchemaNode) {
398 it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
399 (BindingTypes.IDENTIFIABLE_ITEM, parent)));
401 it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
402 (BindingTypes.ITEM, parent)));
403 it.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, it));
407 if (!(schemaNode instanceof GroupingDefinition)) {
408 it.addImplementsType(BindingTypes.augmentable(it));
411 if (schemaNode instanceof DataNodeContainer) {
412 groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings(), genCtx, schemaContext,
413 verboseClassComments, genTypeBuilders, typeProvider);
414 it = addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it, genCtx);
420 static GeneratedTypeBuilder resolveNotification(final GeneratedTypeBuilder listenerInterface, String
421 parentName, final String basePackageName, final NotificationDefinition notification, final Module module,
422 final SchemaContext schemaContext, final boolean verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>>
423 genTypeBuilders, TypeProvider typeProvider, Map<Module, ModuleContext> genCtx) {
425 processUsesAugments(schemaContext, notification, module, genCtx, genTypeBuilders,
426 verboseClassComments, typeProvider);
428 final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition
429 (basePackageName, notification, null, module, genCtx, schemaContext,
430 verboseClassComments, genTypeBuilders, typeProvider);
431 annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
432 notificationInterface.addImplementsType(NOTIFICATION);
433 genCtx.get(module).addChildNodeType(notification, notificationInterface);
435 // Notification object
436 resolveDataSchemaNodes(module, basePackageName, notificationInterface,
437 notificationInterface, notification.getChildNodes(), genCtx, schemaContext,
438 verboseClassComments, genTypeBuilders, typeProvider);
440 //in case of tied notification, incorporate parent's localName
441 final StringBuilder sb = new StringBuilder("on_");
442 if (parentName != null) {
443 sb.append(parentName).append('_');
445 sb.append(notificationInterface.getName());
447 listenerInterface.addMethod(JavaIdentifierNormalizer.normalizeSpecificIdentifier(sb.toString(), JavaIdentifier.METHOD))
448 .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
449 .setComment(encodeAngleBrackets(notification.getDescription())).setReturnType(Types.VOID);
450 return listenerInterface;
454 * Returns reference to generated type builder for specified
455 * <code>schemaNode</code> with <code>packageName</code>.
457 * Firstly the generated type builder is searched in
458 * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
459 * found it is created and added to <code>genTypeBuilders</code>.
462 * string with the package name to which returning generated type
465 * schema node which provide data about the schema node name
466 * @param schemaContext schema context
468 * return type name prefix
469 * @return generated type builder for <code>schemaNode</code>
470 * @throws IllegalArgumentException
472 * <li>if <code>schemaNode</code> is null</li>
473 * <li>if <code>packageName</code> is null</li>
474 * <li>if QName of schema node is null</li>
475 * <li>if schemaNode name is null</li>
479 static GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
480 final SchemaContext schemaContext, final String prefix, final boolean verboseClassComments,
481 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
483 Preconditions.checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
484 Preconditions.checkArgument(packageName != null, "Package Name for Generated Type cannot be NULL.");
485 String schemaNodeName = schemaNode.getQName().getLocalName();
486 Preconditions.checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL.");
488 if (prefix != null && !prefix.isEmpty()) {
489 // underscore used as separator for distinction of class name parts
490 schemaNodeName = new StringBuilder(prefix).append('_').append(schemaNodeName).toString();
493 final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, schemaNodeName);
494 final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode);
495 qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
496 newType.addComment(schemaNode.getDescription());
497 newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName(), schemaContext, verboseClassComments));
498 newType.setReference(schemaNode.getReference());
499 newType.setSchemaPath((List<QName>) schemaNode.getPath().getPathFromRoot());
500 newType.setModuleName(module.getName());
502 if (!genTypeBuilders.containsKey(packageName)) {
503 final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
504 builders.put(newType.getName(), newType);
505 genTypeBuilders.put(packageName, builders);
507 final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
508 if (!builders.containsKey(newType.getName())) {
509 builders.put(newType.getName(), newType);
516 private static void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode node,
517 final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Module module,
518 final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean verboseClassComments,
519 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
520 //TODO: implement rest of schema nodes GTO building
521 if (node != null && typeBuilder != null) {
522 if (node instanceof ContainerSchemaNode) {
523 containerToGenType(module, basePackageName, typeBuilder, childOf, (ContainerSchemaNode) node,
524 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
525 } else if (node instanceof LeafSchemaNode) {
526 resolveLeafSchemaNodeAsMethod(schemaContext, typeBuilder, genCtx, (LeafSchemaNode) node, module,
528 } else if (node instanceof ListSchemaNode) {
529 listToGenType(module, basePackageName, typeBuilder, childOf, (ListSchemaNode) node, schemaContext,
530 verboseClassComments, genCtx, genTypeBuilders, typeProvider);
536 private static void containerToGenType(final Module module, final String basePackageName,
537 final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node,
538 final SchemaContext schemaContext, final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
539 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
541 final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
542 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
543 if (genType != null) {
544 constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), genType, node.getStatus());
545 resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes(), genCtx,
546 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
550 private static void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder
551 parent, final GeneratedTypeBuilder childOf, final ListSchemaNode node, final SchemaContext schemaContext,
552 final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
553 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
554 final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
555 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
556 if (genType != null) {
557 final String nodeName = node.getQName().getLocalName();
558 constructGetter(parent, nodeName, node.getDescription(),
559 Types.listTypeFor(genType), node.getStatus());
560 final List<QName> listKeys = node.getKeyDefinition();
561 final String packageName = new StringBuilder(packageNameForGeneratedType(basePackageName, node.getPath(),
562 BindingNamespaceType.Key)).append('.').append(nodeName).toString();
564 final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node);
566 for (final DataSchemaNode schemaNode : node.getChildNodes()) {
567 if (!schemaNode.isAugmenting()) {
568 addSchemaNodeToListBuilders(nodeName, basePackageName, schemaNode, genType, genTOBuilder, listKeys,
569 module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments);
574 if (genTOBuilder != null) {
575 final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
576 prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder)));
577 genTOBuilder.setSUID(prop);
580 typeBuildersToGenTypes(module, genType, genTOBuilder, genCtx);
584 private static void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
585 final GeneratedTOBuilder genTOBuilder, final Map<Module, ModuleContext> genCtx) {
586 checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
587 if (genTOBuilder != null) {
588 final GeneratedTransferObject genTO = genTOBuilder.toInstance();
589 constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO, Status.CURRENT);
590 genCtx.get(module).addGeneratedTOBuilder(genTOBuilder);
595 * Converts <code>leaf</code> to the getter method which is added to
596 * <code>typeBuilder</code>.
599 * generated type builder to which is added getter method as
600 * <code>leaf</code> mapping
602 * leaf schema node which is mapped as getter method which is
603 * added to <code>typeBuilder</code>
605 * Module in which type was defined
606 * @return boolean value
608 * <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
610 * <li>true - in other cases</li>
613 private static Type resolveLeafSchemaNodeAsMethod(final SchemaContext schemaContext, final GeneratedTypeBuilder
614 typeBuilder, final Map<Module, ModuleContext> genCtx, final LeafSchemaNode leaf, final Module module,
615 final TypeProvider typeProvider) {
616 if (leaf == null || typeBuilder == null || leaf.isAddedByUses()) {
620 final String leafName = leaf.getQName().getLocalName();
621 if (leafName == null) {
625 final Module parentModule = findParentModule(schemaContext, leaf);
626 Type returnType = null;
628 final TypeDefinition<?> typeDef = leaf.getType();
629 if (isInnerType(leaf, typeDef)) {
630 if (typeDef instanceof EnumTypeDefinition) {
631 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
632 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
633 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(),
634 genCtx, typeBuilder, module);
635 if (enumBuilder != null) {
636 returnType = enumBuilder.toInstance(typeBuilder);
638 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
639 } else if (typeDef instanceof UnionTypeDefinition) {
640 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
641 typeProvider, schemaContext);
642 if (genTOBuilder != null) {
643 //TODO: https://bugs.opendaylight.org/show_bug.cgi?id=2289
644 returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule, typeProvider);
646 } else if (typeDef instanceof BitsTypeDefinition) {
647 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
648 typeProvider, schemaContext);
649 if (genTOBuilder != null) {
650 returnType = genTOBuilder.toInstance();
653 // It is constrained version of already declared type (inner declared type exists,
654 // onlyfor special cases (Enum, Union, Bits), which were already checked.
655 // In order to get proper class we need to look up closest derived type
656 // and apply restrictions from leaf type
657 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
658 returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
662 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
663 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
666 if (returnType == null) {
670 if (typeDef instanceof EnumTypeDefinition) {
671 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
674 String leafDesc = leaf.getDescription();
675 if (leafDesc == null) {
679 constructGetter(typeBuilder, leafName, leafDesc, returnType, leaf.getStatus());
684 * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
685 * or to <code>genTOBuilder</code> as property.
688 * string contains the name of list
689 * @param basePackageName
690 * string contains the module package name
692 * data schema node which should be added as getter method to
693 * <code>typeBuilder</code> or as a property to
694 * <code>genTOBuilder</code> if is part of the list key
696 * generated type builder for the list schema node
697 * @param genTOBuilder
698 * generated TO builder for the list keys
700 * list of string which contains QNames of the list keys
703 * @param typeProvider
704 * provider that defines contract for generated types
705 * @param schemaContext
708 * map of generated entities in context of YANG modules
709 * @param genTypeBuilders
710 * map of generated type builders
711 * @param verboseClassComments
712 * generate verbose comments
713 * @throws IllegalArgumentException
715 * <li>if <code>schemaNode</code> equals null</li>
716 * <li>if <code>typeBuilder</code> equals null</li>
719 private static void addSchemaNodeToListBuilders(final String nodeName, final String basePackageName,
720 final DataSchemaNode schemaNode, final GeneratedTypeBuilder typeBuilder,
721 final GeneratedTOBuilder genTOBuilder, final List<QName> listKeys, final Module module,
722 final TypeProvider typeProvider, final SchemaContext schemaContext, final Map<Module, ModuleContext> genCtx,
723 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final boolean verboseClassComments) {
724 checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
725 checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
727 if (schemaNode instanceof LeafSchemaNode) {
728 final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
729 final QName leafQName = leaf.getQName();
730 final String leafName = leafQName.getLocalName();
731 String leafPckgName = basePackageName;
732 boolean isKeyPart = false;
733 if (listKeys.contains(leafQName)) {
734 leafPckgName = new StringBuilder(leafPckgName).append('.').append(BindingNamespaceType.Key).append('.')
735 .append(nodeName).toString();
738 leafPckgName = new StringBuilder(leafPckgName).append('.').append(BindingNamespaceType.Data).append('.')
739 .append(nodeName).toString();
742 final String leafGTOName = new StringBuilder(nodeName).append('_').append(leafName).toString();
743 final GeneratedTypeBuilder leafGTp = new GeneratedTypeBuilderImpl(leafPckgName, leafGTOName);
744 resolveLeafSchemaNodeAsMethod(schemaContext, leafGTp, genCtx, leaf, module,
747 constructGetter(typeBuilder, leafGTOName, schemaNode.getDescription(), leafGTp, Status.CURRENT);
750 AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, leafGTp, true);
752 } else if (!schemaNode.isAddedByUses()) {
753 //TODO: implement leaf list to generated type
754 //TODO: implement choice to generated type
755 if (schemaNode instanceof ContainerSchemaNode) {
756 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode,
757 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
758 } else if (schemaNode instanceof ListSchemaNode) {
759 listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode,
760 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
765 private static TypeDefinition<?> getBaseOrDeclaredType(final TypeDefinition<?> typeDef) {
766 final TypeDefinition<?> baseType = typeDef.getBaseType();
767 return (baseType != null && baseType.getBaseType() != null) ? baseType : typeDef;
770 @SuppressWarnings({ "rawtypes", "unchecked" })
771 private static GeneratedTypeBuilder processDataSchemaNode(final Module module, final String basePackageName,
772 final GeneratedTypeBuilder childOf, final DataSchemaNode node, final SchemaContext schemaContext,
773 final boolean verboseClassComments, Map<Module, ModuleContext> genCtx, final Map<String, Map<String,
774 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
776 if (node.isAugmenting() || node.isAddedByUses()) {
779 final String packageName = packageNameForGeneratedType(basePackageName, node.getPath(), BindingNamespaceType.Data);
780 final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf, module,
781 genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
782 genType.addComment(node.getDescription());
783 annotateDeprecatedIfNecessary(node.getStatus(), genType);
784 genType.setDescription(createDescription(node, genType.getFullyQualifiedName(), schemaContext, verboseClassComments));
785 genType.setModuleName(module.getName());
786 genType.setReference(node.getReference());
787 genType.setSchemaPath((List) node.getPath().getPathFromRoot());
788 genType.setParentTypeForBuilder(childOf);
789 if (node instanceof DataNodeContainer) {
790 genCtx.get(module).addChildNodeType(node, genType);
791 genCtx = groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings(), genCtx, schemaContext,
792 verboseClassComments, genTypeBuilders, typeProvider);
793 processUsesAugments(schemaContext, (DataNodeContainer) node, module, genCtx, genTypeBuilders,
794 verboseClassComments, typeProvider);
800 * Converts all <b>groupings</b> of the module to the list of
801 * <code>Type</code> objects. Firstly are groupings sorted according mutual
802 * dependencies. At least dependent (independent) groupings are in the list
803 * saved at first positions. For every grouping the record is added to map
804 * {@link ModuleContext#groupings allGroupings}
809 * collection of groupings from which types will be generated
810 * @param typeProvider
811 * provider that defines contract for generated types
812 * @param schemaContext
815 * map of generated entities in context of YANG modules
816 * @param genTypeBuilders
817 * map of generated type builders
818 * @param verboseClassComments
819 * generate verbose comments
822 static Map<Module, ModuleContext> groupingsToGenTypes(final Module module, final Collection<GroupingDefinition>
823 groupings, Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
824 verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
825 final String basePackageName = BindingMapping.getRootPackageName(module);
826 final List<GroupingDefinition> groupingsSortedByDependencies = new GroupingDefinitionDependencySort()
828 for (final GroupingDefinition grouping : groupingsSortedByDependencies) {
829 genCtx = groupingToGenType(basePackageName, grouping, module, genCtx, schemaContext,
830 verboseClassComments, genTypeBuilders, typeProvider);
836 * Converts individual grouping to GeneratedType. Firstly generated type
837 * builder is created and every child node of grouping is resolved to the
840 * @param basePackageName
841 * string contains the module package name
843 * GroupingDefinition which contains data about grouping
846 * @param typeProvider
847 * provider that defines contract for generated types
848 * @param schemaContext
851 * map of generated entities in context of YANG modules
852 * @param genTypeBuilders
853 * map of generated type builders
854 * @param verboseClassComments
855 * generate verbose comments
857 * @return GeneratedType which is generated from grouping (object of type
858 * <code>GroupingDefinition</code>)
860 private static Map<Module, ModuleContext> groupingToGenType(final String basePackageName, final GroupingDefinition grouping, final Module
861 module, Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
862 verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
863 final String packageName = packageNameForGeneratedType(basePackageName, grouping.getPath(), BindingNamespaceType.Grouping);
864 final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, grouping, module, genCtx,
865 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
866 annotateDeprecatedIfNecessary(grouping.getStatus(), genType);
867 genCtx.get(module).addGroupingType(grouping.getPath(), genType);
868 resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes(), genCtx,
869 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
870 genCtx = groupingsToGenTypes(module, grouping.getGroupings(), genCtx, schemaContext, verboseClassComments,
871 genTypeBuilders, typeProvider);
872 genCtx = processUsesAugments(schemaContext, grouping, module, genCtx, genTypeBuilders, verboseClassComments,