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.HashMap;
33 import java.util.List;
35 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
36 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
37 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
38 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
39 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
40 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
41 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
42 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
43 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
44 import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier;
45 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
46 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
47 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
48 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
49 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.EnumBuilder;
50 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedPropertyBuilder;
51 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder;
52 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
53 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
54 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
55 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentable;
56 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
57 import org.opendaylight.yangtools.yang.common.QName;
58 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
59 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
60 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
61 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
62 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
63 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
64 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
65 import org.opendaylight.yangtools.yang.model.api.Module;
66 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
67 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
68 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
69 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
70 import org.opendaylight.yangtools.yang.model.api.Status;
71 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
72 import org.opendaylight.yangtools.yang.model.api.UsesNode;
73 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
74 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
75 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
76 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
79 * Helper util class used for generation of types in Binding spec v2.
82 final class GenHelperUtil {
84 private GenHelperUtil() {
85 throw new UnsupportedOperationException("Util class");
89 * Create GeneratedTypeBuilder object from module argument.
92 * Module object from which builder will be created
94 * @param verboseClassComments
96 * @return <code>GeneratedTypeBuilder</code> which is internal
97 * representation of the module
98 * @throws IllegalArgumentException
101 static GeneratedTypeBuilder moduleToDataType(final Module module, final Map<Module, ModuleContext> genCtx, final boolean verboseClassComments) {
102 Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
104 final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data", verboseClassComments);
105 addImplementedInterfaceFromUses(module, moduleDataTypeBuilder, genCtx);
106 moduleDataTypeBuilder.addImplementsType(BindingTypes.TREE_ROOT);
107 moduleDataTypeBuilder.addComment(module.getDescription());
108 moduleDataTypeBuilder.setDescription(createDescription(module, verboseClassComments));
109 moduleDataTypeBuilder.setReference(module.getReference());
110 return moduleDataTypeBuilder;
114 * Generates type builder for <code>module</code>.
117 * Module which is source of package name for generated type
120 * string which is added to the module class name representation
122 * @param verboseClassComments
123 * @return instance of GeneratedTypeBuilder which represents
124 * <code>module</code>.
125 * @throws IllegalArgumentException
126 * if <code>module</code> is null
128 static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean
129 verboseClassComments) {
130 Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
131 final String packageName = BindingMapping.getRootPackageName(module);
132 // underscore used as separator for distinction of module name parts
133 final String moduleName = new StringBuilder(module.getName()).append('_').append(postfix).toString();
135 final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
136 moduleBuilder.setDescription(createDescription(module, verboseClassComments));
137 moduleBuilder.setReference(module.getReference());
138 moduleBuilder.setModuleName(moduleName);
140 return moduleBuilder;
144 * Adds the implemented types to type builder.
146 * The method passes through the list of <i>uses</i> in
147 * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding
148 * generated type from all groupings
149 * allGroupings} which is added as <i>implements type</i> to
150 * <code>builder</code>
152 * @param dataNodeContainer
153 * element which contains the list of used YANG groupings
155 * builder to which are added implemented types according to
156 * <code>dataNodeContainer</code>
157 * @param genCtx generated context
158 * @return generated type builder with all implemented types
160 static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
161 final GeneratedTypeBuilder builder, final Map<Module, ModuleContext> genCtx) {
162 for (final UsesNode usesNode : dataNodeContainer.getUses()) {
163 final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath(), genCtx).toInstance();
164 if (genType == null) {
165 throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
166 + builder.getName());
168 builder.addImplementsType(genType);
173 static GeneratedTypeBuilder findGroupingByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
174 for (final ModuleContext ctx : genCtx.values()) {
175 final GeneratedTypeBuilder result = ctx.getGrouping(path);
176 if (result != null) {
184 * Adds the methods to <code>typeBuilder</code> which represent subnodes of
185 * node for which <code>typeBuilder</code> was created.
187 * The subnodes aren't mapped to the methods if they are part of grouping or
188 * augment (in this case are already part of them).
192 * @param basePackageName
193 * string contains the module package name
195 * generated type builder which represents any node. The subnodes
196 * of this node are added to the <code>typeBuilder</code> as
197 * methods. The subnode can be of type leaf, leaf-list, list,
202 * set of data schema nodes which are the children of the node
203 * for which <code>typeBuilder</code> was created
204 * @return generated type builder which is the same builder as input
205 * parameter. The getter methods (representing child nodes) could be
208 static GeneratedTypeBuilder resolveDataSchemaNodes(final Module module, final String basePackageName,
209 final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf,
210 final Iterable<DataSchemaNode> schemaNodes, final Map<Module, ModuleContext> genCtx,
211 final SchemaContext schemaContext, final boolean verboseClassComments,
212 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
213 final TypeProvider typeProvider) {
215 if (schemaNodes != null && parent != null) {
216 for (final DataSchemaNode schemaNode : schemaNodes) {
217 if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) {
218 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module, genCtx,
219 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
226 static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
227 schemaNode, final Module module, final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext,
228 final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
229 return addDefaultInterfaceDefinition(packageName, schemaNode, null, module, genCtx, schemaContext,
230 verboseClassComments, genTypeBuilders);
233 static Map<Module, ModuleContext> processUsesAugments(final SchemaContext schemaContext, final
234 DataNodeContainer node, final Module module, Map<Module, ModuleContext> genCtx,
235 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
236 final boolean verboseClassComments, final TypeProvider typeProvider) {
237 final String basePackageName = BindingMapping.getRootPackageName(module);
238 for (final UsesNode usesNode : node.getUses()) {
239 for (final AugmentationSchema augment : usesNode.getAugmentations()) {
240 genCtx = AugmentToGenType.usesAugmentationToGenTypes(schemaContext, basePackageName, augment, module,
241 usesNode, node, genCtx, genTypeBuilders, verboseClassComments, typeProvider);
242 genCtx = processUsesAugments(schemaContext, augment, module, genCtx, genTypeBuilders,
243 verboseClassComments, typeProvider);
249 static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
250 for (final ModuleContext ctx : genCtx.values()) {
251 final GeneratedTypeBuilder result = ctx.getChildNode(path);
252 if (result != null) {
259 static GeneratedTypeBuilder findCaseByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
260 for (final ModuleContext ctx : genCtx.values()) {
261 final GeneratedTypeBuilder result = ctx.getCase(path);
262 if (result != null) {
270 * Returns a generated type builder for an augmentation.
272 * The name of the type builder is equal to the name of augmented node with
273 * serial number as suffix.
277 * @param augmentPackageName
278 * string with contains the package name to which the augment
280 * @param basePackageName
281 * string with the package name to which the augmented node
283 * @param targetTypeRef
286 * augmentation schema which contains data about the child nodes
287 * and uses of augment
288 * @return generated type builder for augment in genCtx
290 static Map<Module, ModuleContext> addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
291 final String basePackageName, final Type targetTypeRef, final AugmentationSchema augSchema,
292 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx) {
294 Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
295 if (augmentBuilders == null) {
296 augmentBuilders = new HashMap<>();
297 genTypeBuilders.put(augmentPackageName, augmentBuilders);
299 String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes());
301 if (augIdentifier == null) {
302 augIdentifier = augGenTypeName(augmentBuilders, targetTypeRef.getName());
305 GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augIdentifier);
307 augTypeBuilder.addImplementsType(BindingTypes.TREE_NODE);
308 augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
309 annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
310 augTypeBuilder = addImplementedInterfaceFromUses(augSchema, augTypeBuilder, genCtx);
312 augTypeBuilder = augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema
314 augmentBuilders.put(augTypeBuilder.getName(), augTypeBuilder);
316 if(!augSchema.getChildNodes().isEmpty()) {
317 genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema);
320 genCtx.get(module).addAugmentType(augTypeBuilder);
325 * Adds the methods to <code>typeBuilder</code> what represents subnodes of
326 * node for which <code>typeBuilder</code> was created.
330 * @param basePackageName
331 * string contains the module package name
333 * generated type builder which represents any node. The subnodes
334 * of this node are added to the <code>typeBuilder</code> as
335 * methods. The subnode can be of type leaf, leaf-list, list,
340 * set of data schema nodes which are the children of the node
341 * for which <code>typeBuilder</code> was created
342 * @return generated type builder which is the same object as the input
343 * parameter <code>typeBuilder</code>. The getter method could be
346 private static GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
347 final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf,
348 final Iterable<DataSchemaNode> schemaNodes) {
349 if (schemaNodes != null && typeBuilder != null) {
350 for (final DataSchemaNode schemaNode : schemaNodes) {
351 if (!schemaNode.isAugmenting()) {
352 //TODO: design decomposition and implement it
353 //addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module);
361 * Instantiates generated type builder with <code>packageName</code> and
362 * <code>schemaNode</code>.
364 * The new builder always implements
365 * {@link TreeNode TreeNode}.<br>
366 * If <code>schemaNode</code> is instance of GroupingDefinition it also
367 * implements {@link Augmentable
369 * If <code>schemaNode</code> is instance of
370 * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
371 * DataNodeContainer} it can also implement nodes which are specified in
375 * string with the name of the package to which
376 * <code>schemaNode</code> belongs.
378 * schema node for which is created generated type builder
380 * parent type (can be null)
381 * @param schemaContext schema context
382 * @return generated type builder <code>schemaNode</code>
384 static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
385 schemaNode, final Type parent, final Module module, final Map<Module, ModuleContext> genCtx,
386 final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
388 GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, schemaContext, "",
389 verboseClassComments, genTypeBuilders);
390 if (parent == null) {
391 it.addImplementsType(BindingTypes.TREE_NODE);
393 if (parent instanceof ListSchemaNode) {
394 it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
395 (BindingTypes.IDENTIFIABLE_ITEM, parent)));
397 it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
398 (BindingTypes.ITEM, parent)));
399 it.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, it));
403 if (!(schemaNode instanceof GroupingDefinition)) {
404 it.addImplementsType(BindingTypes.augmentable(it));
407 if (schemaNode instanceof DataNodeContainer) {
408 //TODO: design decomposition and implement it
409 //groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings());
410 it = addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it, genCtx);
416 static GeneratedTypeBuilder resolveNotification(final GeneratedTypeBuilder listenerInterface, String
417 parentName, final String basePackageName, final NotificationDefinition notification, final Module module,
418 final SchemaContext schemaContext, final boolean verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>>
419 genTypeBuilders, TypeProvider typeProvider, Map<Module, ModuleContext> genCtx) {
421 processUsesAugments(schemaContext, notification, module, genCtx, genTypeBuilders,
422 verboseClassComments, typeProvider);
424 final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition
425 (basePackageName, notification, null, module, genCtx, schemaContext,
426 verboseClassComments, genTypeBuilders);
427 annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
428 notificationInterface.addImplementsType(NOTIFICATION);
429 genCtx.get(module).addChildNodeType(notification, notificationInterface);
431 // Notification object
432 resolveDataSchemaNodes(module, basePackageName, notificationInterface,
433 notificationInterface, notification.getChildNodes(), genCtx, schemaContext,
434 verboseClassComments, genTypeBuilders, typeProvider);
436 //in case of tied notification, incorporate parent's localName
437 final StringBuilder sb = new StringBuilder("on_");
438 if (parentName != null) {
439 sb.append(parentName).append('_');
441 sb.append(notificationInterface.getName());
443 listenerInterface.addMethod(JavaIdentifierNormalizer.normalizeSpecificIdentifier(sb.toString(), JavaIdentifier.METHOD))
444 .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
445 .setComment(encodeAngleBrackets(notification.getDescription())).setReturnType(Types.VOID);
446 return listenerInterface;
450 * Returns reference to generated type builder for specified
451 * <code>schemaNode</code> with <code>packageName</code>.
453 * Firstly the generated type builder is searched in
454 * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
455 * found it is created and added to <code>genTypeBuilders</code>.
458 * string with the package name to which returning generated type
461 * schema node which provide data about the schema node name
462 * @param schemaContext
464 * return type name prefix
465 * @return generated type builder for <code>schemaNode</code>
466 * @throws IllegalArgumentException
468 * <li>if <code>schemaNode</code> is null</li>
469 * <li>if <code>packageName</code> is null</li>
470 * <li>if QName of schema node is null</li>
471 * <li>if schemaNode name is null</li>
475 static GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
476 final SchemaContext schemaContext, final String prefix, final boolean verboseClassComments,
477 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
479 Preconditions.checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
480 Preconditions.checkArgument(packageName != null, "Package Name for Generated Type cannot be NULL.");
481 String schemaNodeName = schemaNode.getQName().getLocalName();
482 Preconditions.checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL.");
484 if (prefix != null && !prefix.isEmpty()) {
485 // underscore used as separator for distinction of class name parts
486 schemaNodeName = new StringBuilder(prefix).append('_').append(schemaNodeName).toString();
489 final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, schemaNodeName);
490 final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode);
491 qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
492 newType.addComment(schemaNode.getDescription());
493 newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName(), schemaContext, verboseClassComments));
494 newType.setReference(schemaNode.getReference());
495 newType.setSchemaPath((List<QName>) schemaNode.getPath().getPathFromRoot());
496 newType.setModuleName(module.getName());
498 if (!genTypeBuilders.containsKey(packageName)) {
499 final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
500 builders.put(newType.getName(), newType);
501 genTypeBuilders.put(packageName, builders);
503 final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
504 if (!builders.containsKey(newType.getName())) {
505 builders.put(newType.getName(), newType);
512 private static void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode node,
513 final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Module module,
514 final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean verboseClassComments,
515 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
516 //TODO: implement rest of schema nodes GTO building
517 if (node != null && typeBuilder != null) {
518 if (node instanceof ContainerSchemaNode) {
519 containerToGenType(module, basePackageName, typeBuilder, childOf, (ContainerSchemaNode) node,
520 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
521 } else if (node instanceof LeafSchemaNode) {
522 resolveLeafSchemaNodeAsMethod(schemaContext, typeBuilder, genCtx, (LeafSchemaNode) node, module,
524 } else if (node instanceof ListSchemaNode) {
525 listToGenType(module, basePackageName, typeBuilder, childOf, (ListSchemaNode) node, schemaContext,
526 verboseClassComments, genCtx, genTypeBuilders, typeProvider);
532 private static void containerToGenType(final Module module, final String basePackageName,
533 final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node,
534 final SchemaContext schemaContext, final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
535 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
537 final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
538 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
539 if (genType != null) {
540 constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), genType, node.getStatus());
541 resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes(), genCtx,
542 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
546 private static void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder
547 parent, final GeneratedTypeBuilder childOf, final ListSchemaNode node, final SchemaContext schemaContext,
548 final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
549 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
550 final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
551 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
552 if (genType != null) {
553 final String nodeName = node.getQName().getLocalName();
554 constructGetter(parent, nodeName, node.getDescription(),
555 Types.listTypeFor(genType), node.getStatus());
556 final List<QName> listKeys = node.getKeyDefinition();
557 final String packageName = new StringBuilder(packageNameForGeneratedType(basePackageName, node.getPath(),
558 BindingNamespaceType.Key)).append('.').append(nodeName).toString();
560 final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node);
562 for (final DataSchemaNode schemaNode : node.getChildNodes()) {
563 if (!schemaNode.isAugmenting()) {
564 addSchemaNodeToListBuilders(nodeName, basePackageName, schemaNode, genType, genTOBuilder, listKeys,
565 module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments);
570 if (genTOBuilder != null) {
571 final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
572 prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder)));
573 genTOBuilder.setSUID(prop);
576 typeBuildersToGenTypes(module, genType, genTOBuilder, genCtx);
580 private static void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
581 final GeneratedTOBuilder genTOBuilder, final Map<Module, ModuleContext> genCtx) {
582 checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
583 if (genTOBuilder != null) {
584 final GeneratedTransferObject genTO = genTOBuilder.toInstance();
585 constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO, Status.CURRENT);
586 genCtx.get(module).addGeneratedTOBuilder(genTOBuilder);
591 * Converts <code>leaf</code> to the getter method which is added to
592 * <code>typeBuilder</code>.
595 * generated type builder to which is added getter method as
596 * <code>leaf</code> mapping
598 * leaf schema node which is mapped as getter method which is
599 * added to <code>typeBuilder</code>
601 * Module in which type was defined
602 * @return boolean value
604 * <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
606 * <li>true - in other cases</li>
609 private static Type resolveLeafSchemaNodeAsMethod(final SchemaContext schemaContext, final GeneratedTypeBuilder
610 typeBuilder, final Map<Module, ModuleContext> genCtx, final LeafSchemaNode leaf, final Module module,
611 final TypeProvider typeProvider) {
612 if (leaf == null || typeBuilder == null || leaf.isAddedByUses()) {
616 final String leafName = leaf.getQName().getLocalName();
617 if (leafName == null) {
621 final Module parentModule = findParentModule(schemaContext, leaf);
622 Type returnType = null;
624 final TypeDefinition<?> typeDef = leaf.getType();
625 if (isInnerType(leaf, typeDef)) {
626 if (typeDef instanceof EnumTypeDefinition) {
627 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
628 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
629 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(),
630 genCtx, typeBuilder, module);
631 if (enumBuilder != null) {
632 returnType = enumBuilder.toInstance(typeBuilder);
634 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
635 } else if (typeDef instanceof UnionTypeDefinition) {
636 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
637 typeProvider, schemaContext);
638 if (genTOBuilder != null) {
639 //TODO: https://bugs.opendaylight.org/show_bug.cgi?id=2289
640 returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule, typeProvider);
642 } else if (typeDef instanceof BitsTypeDefinition) {
643 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
644 typeProvider, schemaContext);
645 if (genTOBuilder != null) {
646 returnType = genTOBuilder.toInstance();
649 // It is constrained version of already declared type (inner declared type exists,
650 // onlyfor special cases (Enum, Union, Bits), which were already checked.
651 // In order to get proper class we need to look up closest derived type
652 // and apply restrictions from leaf type
653 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
654 returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
658 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
659 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
662 if (returnType == null) {
666 if (typeDef instanceof EnumTypeDefinition) {
667 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
670 String leafDesc = leaf.getDescription();
671 if (leafDesc == null) {
675 constructGetter(typeBuilder, leafName, leafDesc, returnType, leaf.getStatus());
676 genCtx.get(module).addChildNodeType(leaf, typeBuilder);
681 * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
682 * or to <code>genTOBuilder</code> as property.
685 * string contains the name of list
686 * @param basePackageName
687 * string contains the module package name
689 * data schema node which should be added as getter method to
690 * <code>typeBuilder</code> or as a property to
691 * <code>genTOBuilder</code> if is part of the list key
693 * generated type builder for the list schema node
694 * @param genTOBuilder
695 * generated TO builder for the list keys
697 * list of string which contains QNames of the list keys
700 * @param typeProvider
701 * provider that defines contract for generated types
702 * @param schemaContext
705 * map of generated entities in context of YANG modules
706 * @param genTypeBuilders
707 * map of generated type builders
708 * @param verboseClassComments
709 * generate verbose comments
710 * @throws IllegalArgumentException
712 * <li>if <code>schemaNode</code> equals null</li>
713 * <li>if <code>typeBuilder</code> equals null</li>
716 private static void addSchemaNodeToListBuilders(final String nodeName, final String basePackageName,
717 final DataSchemaNode schemaNode, final GeneratedTypeBuilder typeBuilder,
718 final GeneratedTOBuilder genTOBuilder, final List<QName> listKeys, final Module module,
719 final TypeProvider typeProvider, final SchemaContext schemaContext, final Map<Module, ModuleContext> genCtx,
720 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final boolean verboseClassComments) {
721 checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
722 checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
724 if (schemaNode instanceof LeafSchemaNode) {
725 final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
726 final QName leafQName = leaf.getQName();
727 final String leafName = leafQName.getLocalName();
728 String leafPckgName = basePackageName;
729 boolean isKeyPart = false;
730 if (listKeys.contains(leafQName)) {
731 leafPckgName = new StringBuilder(leafPckgName).append('.').append(BindingNamespaceType.Key).append('.')
732 .append(nodeName).toString();
735 leafPckgName = new StringBuilder(leafPckgName).append('.').append(BindingNamespaceType.Data).append('.')
736 .append(nodeName).toString();
739 final String leafGTOName = new StringBuilder(nodeName).append('_').append(leafName).toString();
740 final GeneratedTypeBuilder leafGTp = new GeneratedTypeBuilderImpl(leafPckgName, leafGTOName);
741 resolveLeafSchemaNodeAsMethod(schemaContext, leafGTp, genCtx, leaf, module,
744 constructGetter(typeBuilder, leafGTOName, schemaNode.getDescription(), leafGTp, Status.CURRENT);
747 AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, leafGTp, true);
749 } else if (!schemaNode.isAddedByUses()) {
750 //TODO: implement leaf list to generated type
751 //TODO: implement choice to generated type
752 if (schemaNode instanceof ContainerSchemaNode) {
753 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode,
754 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
755 } else if (schemaNode instanceof ListSchemaNode) {
756 listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode,
757 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
762 private static TypeDefinition<?> getBaseOrDeclaredType(final TypeDefinition<?> typeDef) {
763 final TypeDefinition<?> baseType = typeDef.getBaseType();
764 return (baseType != null && baseType.getBaseType() != null) ? baseType : typeDef;
767 @SuppressWarnings({ "rawtypes", "unchecked" })
768 private static GeneratedTypeBuilder processDataSchemaNode(final Module module, final String basePackageName,
769 final GeneratedTypeBuilder childOf, final DataSchemaNode node, final SchemaContext schemaContext,
770 final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx, final Map<String, Map<String,
771 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
773 if (node.isAugmenting() || node.isAddedByUses()) {
776 final String packageName = packageNameForGeneratedType(basePackageName, node.getPath(), BindingNamespaceType.Data);
777 final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf, module,
778 genCtx, schemaContext, verboseClassComments, genTypeBuilders);
779 genType.addComment(node.getDescription());
780 annotateDeprecatedIfNecessary(node.getStatus(), genType);
781 genType.setDescription(createDescription(node, genType.getFullyQualifiedName(), schemaContext, verboseClassComments));
782 genType.setModuleName(module.getName());
783 genType.setReference(node.getReference());
784 genType.setSchemaPath((List) node.getPath().getPathFromRoot());
785 if (node instanceof DataNodeContainer) {
786 genCtx.get(module).addChildNodeType(node, genType);
787 //TODO: implement groupings to GTO building first
788 // groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
789 processUsesAugments(schemaContext, (DataNodeContainer) node, module, genCtx, genTypeBuilders,
790 verboseClassComments, typeProvider);