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 java.util.Objects.requireNonNull;
13 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.addTOToTypeBuilder;
14 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.annotateDeprecatedIfNecessary;
15 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.constructGetter;
16 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createReturnTypeForUnion;
17 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.getAugmentIdentifier;
18 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.isInnerType;
19 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.qNameConstant;
20 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveInnerEnumFromTypeDefinition;
21 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveListKeyTOBuilder;
22 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveListKeyTypeBuilder;
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.IDENTIFIABLE;
27 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.IDENTIFIER;
28 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.NOTIFICATION;
29 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.parameterizedTypeFor;
30 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.wildcardTypeFor;
31 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.resolveRegExpressions;
32 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
34 import com.google.common.annotations.Beta;
35 import com.google.common.base.Preconditions;
37 import java.util.Collection;
38 import java.util.HashMap;
39 import java.util.List;
42 import java.util.stream.Collectors;
43 import javax.annotation.Nullable;
45 import org.opendaylight.mdsal.binding.javav2.generator.context.ModuleContext;
46 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
47 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
48 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
49 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
50 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
51 import org.opendaylight.mdsal.binding.javav2.generator.util.ReferencedTypeImpl;
52 import org.opendaylight.mdsal.binding.javav2.generator.util.TypeComments;
53 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
54 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
55 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
56 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.BaseYangTypes;
57 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.GroupingDefinitionDependencySort;
58 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
59 import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier;
60 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
61 import org.opendaylight.mdsal.binding.javav2.model.api.ParameterizedType;
62 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
63 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
64 import org.opendaylight.mdsal.binding.javav2.model.api.YangSourceDefinition;
65 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.EnumBuilder;
66 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedPropertyBuilder;
67 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder;
68 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
69 import org.opendaylight.mdsal.binding.javav2.spec.base.BaseIdentity;
70 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
71 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
72 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentable;
73 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
74 import org.opendaylight.yangtools.yang.common.QName;
75 import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
76 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
77 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
78 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
79 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
80 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
81 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
82 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
83 import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
84 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
85 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
86 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
87 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
88 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
89 import org.opendaylight.yangtools.yang.model.api.Module;
90 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
91 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
92 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
93 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
94 import org.opendaylight.yangtools.yang.model.api.Status;
95 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
96 import org.opendaylight.yangtools.yang.model.api.UsesNode;
97 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
98 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
99 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
100 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
101 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
102 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
105 * Helper util class used for generation of types in Binding spec v2.
108 final class GenHelperUtil {
110 private GenHelperUtil() {
111 throw new UnsupportedOperationException("Util class");
115 * Create GeneratedTypeBuilder object from module argument.
117 * @param module Module object from which builder will be created
118 * @param genCtx generated context
119 * @param verboseClassComments verbosity switch
120 * @return <code>GeneratedTypeBuilder</code> which is internal
121 * representation of the module
122 * @throws IllegalArgumentException if module is null
124 static GeneratedTypeBuilder moduleToDataType(final Module module, final Map<Module, ModuleContext> genCtx,
125 final boolean verboseClassComments) {
126 Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
128 final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data", verboseClassComments,
130 addImplementedInterfaceFromUses(module, moduleDataTypeBuilder, genCtx);
131 moduleDataTypeBuilder.addImplementsType(BindingTypes.TREE_ROOT);
133 if (verboseClassComments) {
134 YangSourceDefinition.of(module).ifPresent(moduleDataTypeBuilder::setYangSourceDefinition);
135 TypeComments.description(module).ifPresent(moduleDataTypeBuilder::addComment);
136 module.getDescription().ifPresent(moduleDataTypeBuilder::setDescription);
137 module.getReference().ifPresent(moduleDataTypeBuilder::setReference);
140 return moduleDataTypeBuilder;
144 * Generates type builder for <code>module</code>.
146 * @param module Module which is source of package name for generated type
148 * @param postfix string which is added to the module class name representation
150 * @param verboseClassComments verbosity switch
151 * @return instance of GeneratedTypeBuilder which represents
152 * <code>module</code>.
153 * @throws IllegalArgumentException if <code>module</code> is null
155 static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean
156 verboseClassComments, final ModuleContext context) {
157 Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
158 final String packageName = BindingMapping.getRootPackageName(module);
159 // underscore used as separator for distinction of module name parts
160 final String moduleName = new StringBuilder(module.getName()).append('_').append(postfix).toString();
162 final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName, context);
163 if (verboseClassComments) {
164 YangSourceDefinition.of(module).ifPresent(moduleBuilder::setYangSourceDefinition);
165 TypeComments.description(module).ifPresent(moduleBuilder::addComment);
166 module.getDescription().ifPresent(moduleBuilder::setDescription);
167 module.getReference().ifPresent(moduleBuilder::setReference);
169 moduleBuilder.setModuleName(moduleName);
170 return moduleBuilder;
174 * Adds the implemented types to type builder.
177 * The method passes through the list of <i>uses</i> in
178 * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding
179 * generated type from all groupings
180 * allGroupings} which is added as <i>implements type</i> to
181 * <code>builder</code>
183 * @param dataNodeContainer element which contains the list of used YANG groupings
184 * @param builder builder to which are added implemented types according to
185 * <code>dataNodeContainer</code>
186 * @param genCtx generated context
187 * @return generated type builder with all implemented types
189 static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
190 final GeneratedTypeBuilder builder, final Map<Module,
191 ModuleContext> genCtx) {
192 for (final UsesNode usesNode : dataNodeContainer.getUses()) {
193 final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath(), genCtx).toInstance();
194 if (genType == null) {
195 throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
196 + builder.getName());
198 builder.addImplementsType(genType);
203 static GeneratedTypeBuilder findGroupingByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
204 for (final ModuleContext ctx : genCtx.values()) {
205 final GeneratedTypeBuilder result = ctx.getGrouping(path);
206 if (result != null) {
213 static GeneratedTypeBuilder findIdentityByQname(final QName qname, final Map<Module, ModuleContext> genCtx) {
214 for (final ModuleContext ctx : genCtx.values()) {
215 final GeneratedTypeBuilder result = ctx.getIdentities().get(qname);
216 if (result != null) {
224 * Adds the methods to <code>typeBuilder</code> which represent subnodes of
225 * node for which <code>typeBuilder</code> was created.
228 * The subnodes aren't mapped to the methods if they are part of grouping or
229 * augment (in this case are already part of them).
231 * @param module current module
232 * @param basePackageName string contains the module package name
233 * @param parent generated type builder which represents any node. The subnodes
234 * of this node are added to the <code>typeBuilder</code> as
235 * methods. The subnode can be of type leaf, leaf-list, list,
237 * @param childOf parent type
238 * @param schemaNodes set of data schema nodes which are the children of the node
239 * for which <code>typeBuilder</code> was created
240 * @return generated type builder which is the same builder as input
241 * parameter. The getter methods (representing child nodes) could be
244 static GeneratedTypeBuilder resolveDataSchemaNodes(final Module module, final String basePackageName,
245 final GeneratedTypeBuilder parent, final GeneratedTypeBuilder
247 final Iterable<DataSchemaNode> schemaNodes, final Map<Module,
248 ModuleContext> genCtx,
249 final SchemaContext schemaContext, final boolean
250 verboseClassComments,
251 final Map<String, Map<String, GeneratedTypeBuilder>>
253 final TypeProvider typeProvider, final BindingNamespaceType
256 if (schemaNodes != null && parent != null) {
257 for (final DataSchemaNode schemaNode : schemaNodes) {
258 if (resolveDataSchemaNodesCheck(module, schemaContext, schemaNode)) {
259 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module, genCtx,
260 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
267 static boolean resolveDataSchemaNodesCheck(final Module module, final SchemaContext schemaContext,
268 final DataSchemaNode schemaNode) {
269 if (!schemaNode.isAugmenting()) {
273 final QName qname = schemaNode.getPath().getLastComponent();
274 final Module originalModule = schemaContext.findModule(qname.getModule()).get();
275 return module.equals(originalModule);
278 private static QName createQNameFromSuperNode(final Module module, final Object node, final SchemaNode
280 QName childNodeQName = null;
281 if (node instanceof Module) {
282 childNodeQName = QName.create(((Module) node).getQNameModule(), superChildNode.getQName().getLocalName());
283 } else if (node instanceof SchemaNode) {
284 childNodeQName = QName.create(((SchemaNode) node).getQName(), superChildNode.getQName().getLocalName());
285 } else if (node instanceof AugmentationSchemaNode) {
286 childNodeQName = QName.create(module.getQNameModule(), superChildNode.getQName().getLocalName());
288 throw new IllegalArgumentException("Not support node type:" + node);
291 return childNodeQName;
294 private static void addUsesImplements(final SchemaNode superNode, final Module superModule,
295 final Object node, final Module module, final SchemaContext schemaContext,
296 final Map<Module, ModuleContext> genCtx, final BindingNamespaceType
298 if (superNode instanceof DataNodeContainer) {
299 for (DataSchemaNode superChildNode : ((DataNodeContainer) superNode).getChildNodes()) {
300 if (superChildNode instanceof DataNodeContainer || superChildNode instanceof ChoiceSchemaNode) {
301 final QName childQName = createQNameFromSuperNode(module, node, superChildNode);
302 DataSchemaNode childNode = ((DataNodeContainer) node).getDataChildByName(childQName);
303 requireNonNull(childNode, () -> node + "->" + childQName);
305 final GeneratedTypeBuilder type = genCtx.get(module).getChildNode(childNode.getPath());
306 final GeneratedTypeBuilder superType = genCtx.get(superModule).getChildNode(superChildNode
309 requireNonNull(type, () -> module + "->" + childNode.getPath());
310 requireNonNull(superType, () -> superModule + "->" + superChildNode.getPath());
311 type.addImplementsType(superType);
312 if (superChildNode instanceof ListSchemaNode
313 && !((ListSchemaNode) superChildNode).getKeyDefinition().isEmpty()) {
314 if (BindingNamespaceType.isGrouping(namespaceType)) {
315 genCtx.get(module).getKeyType(childNode.getPath())
316 .addImplementsType(genCtx.get(superModule).getKeyType(superChildNode.getPath()));
317 } else if (BindingNamespaceType.isData(namespaceType)) {
318 genCtx.get(module).getKeyGenTO(childNode.getPath())
319 .addImplementsType(genCtx.get(superModule).getKeyType(superChildNode.getPath()));
322 addUsesImplements(superChildNode, superModule, childNode, module, schemaContext, genCtx,
326 } else if (superNode instanceof ChoiceSchemaNode) {
327 for (CaseSchemaNode superCaseNode : ((ChoiceSchemaNode) superNode).getCases().values()) {
328 final QName childQName = createQNameFromSuperNode(module, node, superCaseNode);
329 CaseSchemaNode caseNode = ((ChoiceSchemaNode) node).getCaseNodeByName(childQName);
330 requireNonNull(caseNode, () -> node + "->" + childQName);
332 final GeneratedTypeBuilder type = genCtx.get(module).getCase(caseNode.getPath());
333 final GeneratedTypeBuilder superType = genCtx.get(superModule).getCase(superCaseNode.getPath());
334 requireNonNull(type, () -> module + "->" + caseNode.getPath());
335 requireNonNull(superType, () -> superModule + "->" + superCaseNode.getPath());
336 type.addImplementsType(superType);
337 addUsesImplements(superCaseNode, superModule, caseNode, module, schemaContext, genCtx, namespaceType);
340 throw new IllegalArgumentException("Not support super node :" + superNode);
344 private static GroupingDefinition findGroupingNodeFromUses(final Module module, final SchemaContext schemaContext,
345 final Object parentNode, final UsesNode usesNode) {
346 SchemaNode groupingNode;
347 if (parentNode instanceof Module) {
348 final Module superModule = schemaContext.findModule(
349 usesNode.getGroupingPath().getLastComponent().getModule()).get();
350 groupingNode = superModule.getGroupings()
351 .stream().filter(grouping -> grouping.getPath().equals(usesNode.getGroupingPath()))
352 .findFirst().orElse(null);
354 //FIXME: Schema path is not unique for Yang 1.1, findDataSchemaNode always does search from data node first.
355 final Iterable<QName> prefixedPath = usesNode.getGroupingPath().getPathFromRoot();
356 final QName current = prefixedPath.iterator().next();
357 final Module targetModule = schemaContext.findModule(current.getModule()).orElse(null);
358 Preconditions.checkArgument(targetModule != null, "Cannot find target module for %s and %s.",
359 current.getNamespace(), current.getRevision());
360 groupingNode = targetModule.getGroupings().stream()
361 .filter(grouping -> grouping.getPath().equals(usesNode.getGroupingPath()))
362 .collect(Collectors.toList()).get(0);
363 if (groupingNode == null) {
364 groupingNode = SchemaContextUtil.findDataSchemaNode(schemaContext, usesNode.getGroupingPath());
368 requireNonNull(groupingNode, () -> module + "->" + usesNode.getGroupingPath());
369 Preconditions.checkState(groupingNode instanceof GroupingDefinition, "%s->%s", module,
370 usesNode.getGroupingPath());
371 return (GroupingDefinition) groupingNode;
374 static Map<Module, ModuleContext> processUsesImplements(final Object node, final Module module,
375 final SchemaContext schemaContext, final Map<Module,
376 ModuleContext> genCtx, final BindingNamespaceType namespaceType) {
377 if (node instanceof DataNodeContainer) {
378 for (final UsesNode usesNode : ((DataNodeContainer) node).getUses()) {
379 final GroupingDefinition grouping = findGroupingNodeFromUses(module, schemaContext, node, usesNode);
380 final Module superModule = SchemaContextUtil.findParentModule(schemaContext, grouping);
381 addUsesImplements(grouping, superModule, node, module, schemaContext, genCtx, namespaceType);
387 static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
388 for (final ModuleContext ctx : genCtx.values()) {
389 final GeneratedTypeBuilder result = ctx.getChildNode(path);
390 if (result != null) {
397 static GeneratedTypeBuilder findCaseByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
398 for (final ModuleContext ctx : genCtx.values()) {
399 final GeneratedTypeBuilder result = ctx.getCase(path);
400 if (result != null) {
407 static Map<Module, ModuleContext> addRawAugmentGenTypeDefinition(final Module module,
408 final String augmentPackageName, final GeneratedTypeBuilder targetTypeBuilder, final SchemaNode targetNode,
409 final List<AugmentationSchemaNode> schemaPathAugmentListEntry, final Map<String, Map<String,
410 GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx,
411 final SchemaContext schemaContext, final boolean verboseClassComments, final TypeProvider typeProvider,
412 final BindingNamespaceType namespaceType) {
414 //pick augmentation grouped by augmentation target, there is always at least one
415 final AugmentationSchemaNode augSchema = schemaPathAugmentListEntry.get(0);
417 //this requires valid semantics in YANG model
418 String augIdentifier = null;
419 for (AugmentationSchemaNode aug : schemaPathAugmentListEntry) {
420 // FIXME: when there're multiple augment identifiers for augmentations of same target,
421 // it would pick the first identifier.
422 augIdentifier = getAugmentIdentifier(aug.getUnknownSchemaNodes());
426 if (augIdentifier == null) {
427 augIdentifier = new StringBuilder(module.getName())
428 .append('_').append(targetNode.getQName().getLocalName()).toString();
431 GeneratedTypeBuilderImpl augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augIdentifier,
432 true, false, genCtx.get(module));
434 augTypeBuilder.addImplementsType(BindingTypes.TREE_NODE);
435 augTypeBuilder.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, augTypeBuilder));
436 augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeBuilder.toInstance()));
437 augTypeBuilder.setBasePackageName(BindingMapping.getRootPackageName(module));
438 augTypeBuilder.setWithBuilder(true);
439 augTypeBuilder.setBindingNamespaceType(namespaceType);
440 annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
442 //If target is case node then pass down parent type (the closest ancestor) to children data nodes.
443 final GeneratedTypeBuilder childOf;
444 if (targetNode instanceof CaseSchemaNode) {
445 childOf = (GeneratedTypeBuilder) targetTypeBuilder.getParentTypeForBuilder();
447 augTypeBuilder.setParentTypeForBuilder(targetTypeBuilder);
448 childOf = targetTypeBuilder;
451 //produces getters for augTypeBuilder eventually
452 for (AugmentationSchemaNode aug : schemaPathAugmentListEntry) {
454 addImplementedInterfaceFromUses(aug, augTypeBuilder, genCtx);
455 augSchemaNodeToMethods(module, BindingMapping.getRootPackageName(module), augTypeBuilder, childOf,
456 aug.getChildNodes(), genCtx, schemaContext, verboseClassComments, typeProvider, genTypeBuilders,
457 targetTypeBuilder.getBindingNamespaceType());
460 final Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.computeIfAbsent(
461 augmentPackageName, k -> new HashMap<>());
463 augmentBuilders.put(augTypeBuilder.getName(), augTypeBuilder);
465 if (!augSchema.getChildNodes().isEmpty()) {
466 genCtx.get(module).addTargetToAugmentation(augTypeBuilder, augSchema.getTargetPath());
468 genCtx.get(module).addAugmentType(augTypeBuilder);
469 genCtx.get(module).addTypeToAugmentations(augTypeBuilder, schemaPathAugmentListEntry);
474 * Adds the methods to <code>typeBuilder</code> what represents subnodes of
475 * node for which <code>typeBuilder</code> was created.
477 * @param module current module
478 * @param basePackageName string contains the module package name
479 * @param typeBuilder generated type builder which represents any node. The subnodes
480 * of this node are added to the <code>typeBuilder</code> as
481 * methods. The subnode can be of type leaf, leaf-list, list,
483 * @param childOf parent type
484 * @param schemaNodes set of data schema nodes which are the children of the node
485 * for which <code>typeBuilder</code> was created
486 * @return generated type builder which is the same object as the input added to it.
488 private static GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
489 final GeneratedTypeBuilder typeBuilder, final
490 GeneratedTypeBuilder childOf, final
491 Iterable<DataSchemaNode> schemaNodes,
492 final Map<Module, ModuleContext> genCtx, final
493 SchemaContext schemaContext, final boolean
494 verboseClassComments, final TypeProvider
495 typeProvider, final Map<String, Map<String,
496 GeneratedTypeBuilder>> genTypeBuilders, final BindingNamespaceType namespaceType) {
497 if (schemaNodes != null && typeBuilder != null) {
498 for (final DataSchemaNode schemaNode : schemaNodes) {
499 if (!schemaNode.isAugmenting()) {
500 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module, genCtx,
501 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
509 * Instantiates generated type builder with <code>packageName</code> and
510 * <code>schemaNode</code>.
513 * The new builder always implements
514 * {@link TreeNode TreeNode}.<br>
515 * If <code>schemaNode</code> is instance of GroupingDefinition it also
516 * implements {@link Augmentable
518 * If <code>schemaNode</code> is instance of
519 * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
520 * DataNodeContainer} it can also implement nodes which are specified in
523 * @param basePackageName string contains the module package name
524 * @param schemaNode schema node for which is created generated type builder
525 * @param childOf parent generated type of data tree node, which should be
526 * set null if current schema node is not a data tree node.
527 * @param schemaContext schema context
528 * @return generated type builder <code>schemaNode</code>
530 public static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String basePackageName, final SchemaNode
531 schemaNode, @Nullable final Type childOf, final Module module, final Map<Module, ModuleContext> genCtx,
532 final SchemaContext schemaContext, final boolean
533 verboseClassComments, final Map<String,
535 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider, final BindingNamespaceType
538 GeneratedTypeBuilder it = addRawInterfaceDefinition(basePackageName, schemaNode, schemaContext, "", "",
539 verboseClassComments, genTypeBuilders, namespaceType, genCtx.get(module));
540 if (BindingNamespaceType.isData(namespaceType)) {
541 if (childOf == null) {
542 it.addImplementsType(BindingTypes.TREE_NODE);
544 if (!(schemaNode instanceof ListSchemaNode)
545 || ((ListSchemaNode) schemaNode).getKeyDefinition().isEmpty()) {
546 it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, childOf,
547 parameterizedTypeFor(BindingTypes.ITEM, it)));
551 if (!(schemaNode instanceof CaseSchemaNode)) {
552 it.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, it));
555 it.addImplementsType(BindingTypes.augmentable(it));
558 if (schemaNode instanceof DataNodeContainer) {
559 groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings(), genCtx, schemaContext,
560 verboseClassComments, genTypeBuilders, typeProvider);
561 it = addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it, genCtx);
567 static GeneratedTypeBuilder resolveNotification(final GeneratedTypeBuilder listenerInterface, final String
568 parentName, final String basePackageName, final NotificationDefinition notification, final Module module,
569 final SchemaContext schemaContext, final boolean
570 verboseClassComments, final Map<String, Map<String,
571 GeneratedTypeBuilder>>
572 genTypeBuilders, final TypeProvider typeProvider, final
573 Map<Module, ModuleContext> genCtx) {
574 final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition(basePackageName, notification,
575 null, module, genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider,
576 BindingNamespaceType.Notification);
577 annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
578 notificationInterface.addImplementsType(NOTIFICATION);
579 genCtx.get(module).addChildNodeType(notification, notificationInterface);
581 // Notification object
582 resolveDataSchemaNodes(module, basePackageName, notificationInterface,
583 notificationInterface, notification.getChildNodes(), genCtx, schemaContext,
584 verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Notification);
586 //in case of tied notification, incorporate parent's localName
587 final StringBuilder sb = new StringBuilder("on_");
588 if (parentName != null) {
589 sb.append(parentName).append('_');
591 sb.append(notificationInterface.getName());
593 listenerInterface.addMethod(JavaIdentifierNormalizer.normalizeSpecificIdentifier(sb.toString(),
594 JavaIdentifier.METHOD))
595 .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
596 .setComment(encodeAngleBrackets(notification.getDescription().orElse(null))).setReturnType(Types.VOID);
597 return listenerInterface;
601 * Returns reference to generated type builder for specified
602 * <code>schemaNode</code> with <code>packageName</code>.
605 * Firstly the generated type builder is searched in
606 * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
607 * found it is created and added to <code>genTypeBuilders</code>.
609 * @param basePackageName string contains the module package name
610 * @param schemaNode schema node which provide data about the schema node name
611 * @param schemaContext schema context
612 * @param prefix return type name prefix
613 * @return generated type builder for <code>schemaNode</code>
614 * @throws IllegalArgumentException <ul>
615 * <li>if <code>schemaNode</code> is null</li>
616 * <li>if <code>packageName</code> is null</li>
617 * <li>if QName of schema node is null</li>
618 * <li>if schemaNode name is null</li>
621 static GeneratedTypeBuilder addRawInterfaceDefinition(final String basePackageName, final SchemaNode schemaNode,
622 final SchemaContext schemaContext, final String prefix,
624 final boolean verboseClassComments, final Map<String,
625 Map<String, GeneratedTypeBuilder>> genTypeBuilders,
626 final BindingNamespaceType namespaceType, final
627 ModuleContext context) {
629 Preconditions.checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
630 Preconditions.checkArgument(basePackageName != null, "Base package Name for Generated Type cannot be NULL.");
631 String schemaNodeName = schemaNode.getQName().getLocalName();
632 Preconditions.checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL.");
634 if (prefix != null && !prefix.isEmpty()) {
635 // underscore used as separator for distinction of class name parts
636 schemaNodeName = new StringBuilder(prefix).append('_').append(schemaNodeName).toString();
639 if (suffix != null && !suffix.isEmpty()) {
640 // underscore used as separator for distinction of class name parts
641 schemaNodeName = new StringBuilder(schemaNodeName).append('_').append(suffix).toString();
644 final String packageName = packageNameForGeneratedType(basePackageName, schemaNode.getPath(), namespaceType);
645 final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, schemaNodeName, context);
646 final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode);
647 qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
648 if (verboseClassComments) {
649 YangSourceDefinition.of(module, schemaNode).ifPresent(newType::setYangSourceDefinition);
650 TypeComments.description(schemaNode).ifPresent(newType::addComment);
651 schemaNode.getDescription().ifPresent(newType::setDescription);
652 schemaNode.getReference().ifPresent(newType::setReference);
654 newType.setSchemaPath((List<QName>) schemaNode.getPath().getPathFromRoot());
655 newType.setModuleName(module.getName());
656 newType.setBasePackageName(BindingMapping.getRootPackageName(module));
657 newType.setWithBuilder(AuxiliaryGenUtils.hasBuilderClass(schemaNode, namespaceType));
658 newType.setBindingNamespaceType(namespaceType);
660 if (!genTypeBuilders.containsKey(packageName)) {
661 final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
662 builders.put(newType.getName(), newType);
663 genTypeBuilders.put(packageName, builders);
665 final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
666 if (!builders.containsKey(newType.getName())) {
667 builders.put(newType.getName(), newType);
674 private static void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode node,
675 final GeneratedTypeBuilder typeBuilder, final
676 GeneratedTypeBuilder childOf, final Module module,
677 final Map<Module, ModuleContext> genCtx, final SchemaContext
678 schemaContext, final boolean verboseClassComments,
679 final Map<String, Map<String, GeneratedTypeBuilder>>
680 genTypeBuilders, final TypeProvider typeProvider,
681 final BindingNamespaceType namespaceType) {
683 if (node != null && typeBuilder != null) {
684 if (node instanceof ContainerSchemaNode) {
685 containerToGenType(module, basePackageName, typeBuilder, childOf, (ContainerSchemaNode) node,
686 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
687 } else if (node instanceof LeafListSchemaNode) {
688 resolveLeafListSchemaNode(schemaContext, typeBuilder, (LeafListSchemaNode) node, module,
689 typeProvider, genCtx, verboseClassComments);
690 } else if (node instanceof LeafSchemaNode) {
691 resolveLeafSchemaNodeAsMethod("", schemaContext, typeBuilder, genCtx, (LeafSchemaNode) node, module,
692 typeProvider, verboseClassComments);
693 } else if (node instanceof ListSchemaNode) {
694 listToGenType(module, basePackageName, typeBuilder, childOf, (ListSchemaNode) node, schemaContext,
695 verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
696 } else if (node instanceof ChoiceSchemaNode) {
697 choiceToGenType(module, schemaContext, verboseClassComments, basePackageName, typeBuilder, childOf,
698 (ChoiceSchemaNode) node, genTypeBuilders, genCtx, typeProvider, namespaceType);
699 } else if (node instanceof AnyXmlSchemaNode || node instanceof AnyDataSchemaNode) {
700 resolveAnyNodeAsMethod(schemaContext, typeBuilder, genCtx, node, module, typeProvider);
706 * Converts <code>choiceNode</code> to the list of generated types for
707 * choice and its cases.
710 * The package names for choice and for its cases are created as
711 * concatenation of the module package (<code>basePackageName</code>) and
712 * names of all parents node.
714 * @param module current module
715 * @param basePackageName string with the module package name
716 * @param parent parent type
717 * @param choiceNode choice node which is mapped to generated type. Also child
718 * nodes - cases are mapped to generated types.
719 * @throws IllegalArgumentException <ul>
720 * <li>if <code>basePackageName</code> is null</li>
721 * <li>if <code>choiceNode</code> is null</li>
724 private static void choiceToGenType(final Module module, final SchemaContext schemaContext, final boolean
725 verboseClasssComments, final String basePackageName, final GeneratedTypeBuilder parent,
726 final GeneratedTypeBuilder childOf, final ChoiceSchemaNode choiceNode,
727 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
728 final Map<Module, ModuleContext> genCtx, final TypeProvider typeProvider,
729 final BindingNamespaceType namespaceType) {
730 checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
731 checkArgument(choiceNode != null, "Choice Schema Node cannot be NULL.");
733 final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(basePackageName, choiceNode,
734 schemaContext, "", "", verboseClasssComments, genTypeBuilders, namespaceType, genCtx.get(module));
735 constructGetter(parent, choiceNode.getQName().getLocalName(),
736 choiceNode.getDescription().orElse(null), choiceTypeBuilder, choiceNode.getStatus());
737 choiceTypeBuilder.setParentTypeForBuilder(childOf);
738 if (BindingNamespaceType.isData(namespaceType)) {
739 choiceTypeBuilder.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, choiceTypeBuilder));
741 annotateDeprecatedIfNecessary(choiceNode.getStatus(), choiceTypeBuilder);
742 genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder);
743 generateTypesFromChoiceCases(module, schemaContext, genCtx, basePackageName, choiceTypeBuilder.toInstance(),
744 choiceNode, verboseClasssComments, typeProvider, genTypeBuilders, namespaceType);
747 private static void containerToGenType(final Module module, final String basePackageName,
748 final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf,
749 final ContainerSchemaNode node,
750 final SchemaContext schemaContext, final boolean verboseClassComments,
751 final Map<Module, ModuleContext> genCtx,
752 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
753 final TypeProvider typeProvider,
754 final BindingNamespaceType namespaceType) {
756 final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
757 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
758 if (genType != null) {
759 StringBuilder getterName = new StringBuilder(node.getQName().getLocalName());
760 constructGetter(parent, getterName.toString(), node.getDescription().orElse(null), genType, node
762 resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes(), genCtx,
763 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
764 processUsesImplements(node, module, schemaContext, genCtx, namespaceType);
768 private static void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder
769 parent, final GeneratedTypeBuilder childOf, final ListSchemaNode node, final SchemaContext schemaContext,
770 final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
771 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final
772 TypeProvider typeProvider,
773 final BindingNamespaceType namespaceType) {
775 final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
776 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
777 if (genType != null) {
778 final String nodeName = node.getQName().getLocalName();
780 Type getterReturnType = Types.listTypeFor(genType);
781 if (BindingNamespaceType.isGrouping(namespaceType)) {
782 getterReturnType = Types.listTypeFor(wildcardTypeFor(genType.getPackageName(), genType.getName(),
785 constructGetter(parent, nodeName, node.getDescription().orElse(null), getterReturnType, node.getStatus());
787 final List<QName> listKeys = node.getKeyDefinition();
788 final String packageName = new StringBuilder(packageNameForGeneratedType(basePackageName, node.getPath(),
789 BindingNamespaceType.Key)).append('.').append(nodeName).toString();
790 //FIXME: Is it neccessary to generate interface of key and implemented by class?
791 if (BindingNamespaceType.isGrouping(namespaceType)) {
792 final GeneratedTypeBuilder genTypeBuilder = resolveListKeyTypeBuilder(packageName, node,
794 for (final DataSchemaNode schemaNode : node.getChildNodes()) {
795 if (resolveDataSchemaNodesCheck(module, schemaContext, schemaNode)) {
796 addSchemaNodeToListTypeBuilders(nodeName, basePackageName, schemaNode, genType,
797 genTypeBuilder, listKeys,
798 module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments,
802 if (genTypeBuilder != null) {
803 typeBuildersToGenTypes(module, genType, genTypeBuilder.toInstance(), genCtx, namespaceType);
804 genCtx.get(module).addKeyType(node.getPath(), genTypeBuilder);
806 processUsesImplements(node, module, schemaContext, genCtx, namespaceType);
808 final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node, genCtx.get(module));
809 if (genTOBuilder != null) {
810 final Type identifiableMarker = Types.parameterizedTypeFor(IDENTIFIABLE, genTOBuilder);
811 genTOBuilder.addImplementsType(IDENTIFIER);
812 genType.addImplementsType(identifiableMarker);
813 if (BindingNamespaceType.isData(namespaceType)) {
814 genType.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, childOf,
815 parameterizedTypeFor(BindingTypes.IDENTIFIABLE_ITEM, genType, genTOBuilder)));
819 for (final DataSchemaNode schemaNode : node.getChildNodes()) {
820 if (resolveDataSchemaNodesCheck(module, schemaContext, schemaNode)) {
821 addSchemaNodeToListBuilders(nodeName, basePackageName, schemaNode, genType, genTOBuilder,
823 module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments,
827 processUsesImplements(node, module, schemaContext, genCtx, namespaceType);
830 if (genTOBuilder != null) {
831 final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
832 prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder)));
833 genTOBuilder.setSUID(prop);
834 typeBuildersToGenTypes(module, genType, genTOBuilder.toInstance(), genCtx, namespaceType);
835 genCtx.get(module).addGeneratedTOBuilder(node.getPath(), genTOBuilder);
841 private static void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
842 final Type keyType, final Map<Module, ModuleContext> genCtx,
843 final BindingNamespaceType namespaceType) {
844 checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
845 if (keyType != null) {
846 Type returnKeyType = keyType;
847 if (BindingNamespaceType.isGrouping(namespaceType)) {
848 returnKeyType = wildcardTypeFor(keyType.getPackageName(), keyType.getName(),
851 constructGetter(typeBuilder, "identifier", "Returns Primary Key of Yang List Type", returnKeyType, Status
857 private static void addPatternConstant(final GeneratedTypeBuilder typeBuilder, final String leafName,
858 final List<PatternConstraint> patternConstraints) {
859 if (!patternConstraints.isEmpty()) {
860 final StringBuilder field = new StringBuilder();
861 field.append(BindingMapping.PATTERN_CONSTANT_NAME).append("_")
862 .append(JavaIdentifierNormalizer.normalizeSpecificIdentifier(leafName, JavaIdentifier.METHOD));
863 typeBuilder.addConstant(Types.listTypeFor(BaseYangTypes.STRING_TYPE), field.toString(),
864 resolveRegExpressions(patternConstraints));
869 * Converts <code>leaf</code> to the getter method which is added to
870 * <code>typeBuilder</code>.
872 * @param typeBuilder generated type builder to which is added getter method as
873 * <code>leaf</code> mapping
874 * @param leaf leaf schema node which is mapped as getter method which is
875 * added to <code>typeBuilder</code>
876 * @param module Module in which type was defined
877 * @return boolean value
879 * <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
881 * <li>true - in other cases</li>
884 private static Type resolveLeafSchemaNodeAsMethod(final String nodeName, final SchemaContext schemaContext,
885 final GeneratedTypeBuilder typeBuilder, final Map<Module,
886 ModuleContext> genCtx, final LeafSchemaNode leaf,
887 final Module module, final TypeProvider typeProvider, final
888 boolean verboseClassComments) {
889 if (leaf == null || typeBuilder == null) {
893 final String leafName = leaf.getQName().getLocalName();
894 if (leafName == null) {
898 final Module parentModule = findParentModule(schemaContext, leaf);
899 Type returnType = null;
901 final TypeDefinition<?> typeDef = leaf.getType();
903 if (leaf.isAddedByUses()) {
904 Preconditions.checkState(leaf instanceof DerivableSchemaNode);
905 if (isInnerType(leaf, typeDef)) {
906 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
907 returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
908 restrictions, genCtx.get(module));
910 if (typeDef.getBaseType() == null && (typeDef instanceof EnumTypeDefinition
911 || typeDef instanceof UnionTypeDefinition || typeDef instanceof BitsTypeDefinition)) {
912 LeafSchemaNode originalLeaf = (LeafSchemaNode) ((DerivableSchemaNode) leaf).getOriginal()
914 requireNonNull(originalLeaf);
915 returnType = genCtx.get(findParentModule(schemaContext, originalLeaf)).getInnerType(typeDef
918 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
919 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions,
923 } else if (isInnerType(leaf, typeDef)) {
924 if (typeDef instanceof EnumTypeDefinition) {
925 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, genCtx.get(module));
926 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
927 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(),
928 genCtx, typeBuilder, module);
929 if (enumBuilder != null) {
930 returnType = enumBuilder.toInstance(typeBuilder);
932 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
933 } else if (typeDef instanceof UnionTypeDefinition) {
934 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
935 typeProvider, schemaContext, genCtx.get(module), genCtx);
936 if (genTOBuilder != null) {
937 //TODO: https://bugs.opendaylight.org/show_bug.cgi?id=2289
938 returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule,
939 typeProvider, verboseClassComments);
941 } else if (typeDef instanceof BitsTypeDefinition) {
942 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
943 typeProvider, schemaContext, genCtx.get(module), genCtx);
944 if (genTOBuilder != null) {
945 returnType = genTOBuilder.toInstance();
948 // It is constrained version of already declared type (inner declared type exists,
949 // onlyfor special cases (Enum, Union, Bits), which were already checked.
950 // In order to get proper class we need to look up closest derived type
951 // and apply restrictions from leaf type
952 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
953 returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
954 restrictions, genCtx.get(module));
955 addPatternConstant(typeBuilder, leafName, restrictions.getPatternConstraints());
958 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
959 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions, genCtx.get(module));
960 addPatternConstant(typeBuilder, leafName, restrictions.getPatternConstraints());
963 if (returnType == null) {
967 if (typeDef instanceof EnumTypeDefinition) {
968 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
971 final String leafGetterName;
972 if ("key".equals(leafName.toLowerCase())) {
973 StringBuilder sb = new StringBuilder(leafName)
974 .append('_').append("RESERVED_WORD");
975 leafGetterName = sb.toString();
977 leafGetterName = leafName;
979 constructGetter(typeBuilder, leafGetterName, leaf.getDescription().orElse(""), returnType, leaf.getStatus());
984 * Converts <code>node</code> leaf list schema node to getter method of
985 * <code>typeBuilder</code>.
987 * @param typeBuilder generated type builder to which is <code>node</code> added as
989 * @param node leaf list schema node which is added to
990 * <code>typeBuilder</code> as getter method
991 * @param module module
992 * @param typeProvider type provider instance
993 * @param genCtx actual generated context
994 * @return boolean value
996 * <li>true - if <code>node</code>, <code>typeBuilder</code>,
997 * nodeName equal null or <code>node</code> is added by <i>uses</i></li>
998 * <li>false - other cases</li>
1001 private static boolean resolveLeafListSchemaNode(final SchemaContext schemaContext, final GeneratedTypeBuilder
1002 typeBuilder, final LeafListSchemaNode node, final Module module, final TypeProvider typeProvider,
1003 final Map<Module, ModuleContext> genCtx, final boolean
1004 verboseClassComments) {
1005 if (node == null || typeBuilder == null) {
1009 final QName nodeName = node.getQName();
1011 final TypeDefinition<?> typeDef = node.getType();
1012 final Module parentModule = findParentModule(schemaContext, node);
1014 Type returnType = null;
1015 if (typeDef.getBaseType() == null) {
1016 if (typeDef instanceof EnumTypeDefinition) {
1017 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, genCtx.get(module));
1018 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
1019 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName,
1020 genCtx, typeBuilder, module);
1021 returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName(), true,
1023 ((TypeProviderImpl) typeProvider).putReferencedType(node.getPath(), returnType);
1024 } else if (typeDef instanceof UnionTypeDefinition) {
1025 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule,
1026 typeProvider, schemaContext, genCtx.get(module), genCtx);
1027 if (genTOBuilder != null) {
1028 returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule,
1029 typeProvider, verboseClassComments);
1031 } else if (typeDef instanceof BitsTypeDefinition) {
1032 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule,
1033 typeProvider, schemaContext, genCtx.get(module), genCtx);
1034 returnType = genTOBuilder.toInstance();
1036 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
1037 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions,
1038 genCtx.get(module));
1040 addPatternConstant(typeBuilder, nodeName.getLocalName(), restrictions.getPatternConstraints());
1043 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
1044 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions, genCtx.get(module));
1046 addPatternConstant(typeBuilder, nodeName.getLocalName(), restrictions.getPatternConstraints());
1049 final ParameterizedType listType = Types.listTypeFor(returnType);
1050 constructGetter(typeBuilder, nodeName.getLocalName(), node.getDescription().orElse(null), listType, node
1056 * Converts <code>caseNodes</code> set to list of corresponding generated
1060 * For every <i>case</i> which isn't added through augment or <i>uses</i> is
1061 * created generated type builder. The package names for the builder is
1062 * created as concatenation of the module package (
1063 * <code>basePackageName</code>) and names of all parents nodes of the
1064 * concrete <i>case</i>. There is also relation "<i>implements type</i>"
1065 * between every case builder and <i>choice</i> type
1067 * @param module current module
1068 * @param schemaContext current schema context
1069 * @param genCtx actual generated context
1070 * @param basePackageName string with the module package name
1071 * @param refChoiceType type which represents superior <i>case</i>
1072 * @param choiceNode choice case node which is mapped to generated type
1073 * @param verboseClassComments Javadoc verbosity switch
1074 * @throws IllegalArgumentException <ul>
1075 * <li>if <code>basePackageName</code> equals null</li>
1076 * <li>if <code>refChoiceType</code> equals null</li>
1077 * <li>if <code>caseNodes</code> equals null</li>
1080 private static void generateTypesFromChoiceCases(final Module module, final SchemaContext schemaContext,
1081 final Map<Module, ModuleContext> genCtx, final String
1082 basePackageName, final GeneratedType refChoiceType,
1083 final ChoiceSchemaNode choiceNode, final boolean
1084 verboseClassComments,
1085 final TypeProvider typeProvider, final Map<String, Map<String,
1086 GeneratedTypeBuilder>> genTypeBuilders,
1087 final BindingNamespaceType namespaceType) {
1088 checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
1089 checkArgument(refChoiceType != null, "Referenced Choice Type cannot be NULL.");
1090 checkArgument(choiceNode != null, "ChoiceNode cannot be NULL.");
1092 for (final CaseSchemaNode caseNode : choiceNode.getCases().values()) {
1093 if (caseNode != null && resolveDataSchemaNodesCheck(module, schemaContext, caseNode)) {
1094 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(basePackageName, caseNode,
1095 null, module, genCtx, schemaContext, verboseClassComments,
1096 genTypeBuilders, typeProvider, namespaceType);
1097 caseTypeBuilder.addImplementsType(refChoiceType);
1098 caseTypeBuilder.setParentTypeForBuilder(refChoiceType.getParentTypeForBuilder());
1099 annotateDeprecatedIfNecessary(caseNode.getStatus(), caseTypeBuilder);
1100 genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder);
1101 if (BindingNamespaceType.isData(namespaceType)) {
1102 genCtx.get(module).addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode);
1105 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder,
1106 (GeneratedTypeBuilder) refChoiceType.getParentTypeForBuilder(), caseNode.getChildNodes(),
1107 genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
1108 processUsesImplements(caseNode, module, schemaContext, genCtx, namespaceType);
1113 private static Type resolveAnyNodeAsMethod(final SchemaContext schemaContext, final GeneratedTypeBuilder
1114 typeBuilder, final Map<Module, ModuleContext> genCtx, final DataSchemaNode node, final Module module,
1115 final TypeProvider typeProvider) {
1117 final String anyName = node.getQName().getLocalName();
1118 if (anyName == null) {
1122 Type returnType = Types.DOCUMENT;
1123 constructGetter(typeBuilder, anyName, node.getDescription().orElse(""), returnType, node.getStatus());
1128 * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
1129 * or to <code>genTOBuilder</code> as property.
1131 * @param nodeName string contains the name of list
1132 * @param basePackageName string contains the module package name
1133 * @param schemaNode data schema node which should be added as getter method to
1134 * <code>typeBuilder</code> or as a property to
1135 * <code>genTOBuilder</code> if is part of the list key
1136 * @param typeBuilder generated type builder for the list schema node
1137 * @param genTOBuilder generated TO builder for the list keys
1138 * @param listKeys list of string which contains QNames of the list keys
1139 * @param module current module
1140 * @param typeProvider provider that defines contract for generated types
1141 * @param schemaContext schema context
1142 * @param genCtx map of generated entities in context of YANG modules
1143 * @param genTypeBuilders map of generated type builders
1144 * @param verboseClassComments generate verbose comments
1145 * @throws IllegalArgumentException <ul>
1146 * <li>if <code>schemaNode</code> equals null</li>
1147 * <li>if <code>typeBuilder</code> equals null</li>
1150 private static void addSchemaNodeToListBuilders(final String nodeName, final String basePackageName,
1151 final DataSchemaNode schemaNode, final GeneratedTypeBuilder
1153 final GeneratedTOBuilder genTOBuilder, final List<QName>
1154 listKeys, final Module module,
1155 final TypeProvider typeProvider, final SchemaContext
1156 schemaContext, final Map<Module, ModuleContext> genCtx,
1157 final Map<String, Map<String, GeneratedTypeBuilder>>
1158 genTypeBuilders, final boolean verboseClassComments,
1159 final BindingNamespaceType namespaceType) {
1160 checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
1161 checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
1163 if (schemaNode instanceof LeafSchemaNode) {
1164 final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
1165 final QName leafQName = leaf.getQName();
1167 final Type type = resolveLeafSchemaNodeAsMethod(nodeName, schemaContext, typeBuilder, genCtx, leaf, module,
1168 typeProvider, verboseClassComments);
1169 if (listKeys.contains(leafQName)) {
1171 resolveLeafSchemaNodeAsProperty(nodeName, schemaContext, typeProvider, genCtx, genTOBuilder,
1175 AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(nodeName, genTOBuilder, leaf, type, true);
1179 if (schemaNode instanceof LeafListSchemaNode) {
1180 resolveLeafListSchemaNode(schemaContext, typeBuilder, (LeafListSchemaNode) schemaNode, module,
1181 typeProvider, genCtx, verboseClassComments);
1182 } else if (schemaNode instanceof ContainerSchemaNode) {
1183 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode,
1184 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
1185 } else if (schemaNode instanceof ListSchemaNode) {
1186 listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode,
1187 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
1188 } else if (schemaNode instanceof ChoiceSchemaNode) {
1189 choiceToGenType(module, schemaContext, verboseClassComments, basePackageName, typeBuilder, typeBuilder,
1190 (ChoiceSchemaNode) schemaNode, genTypeBuilders, genCtx, typeProvider, namespaceType);
1195 private static void addSchemaNodeToListTypeBuilders(final String nodeName, final String basePackageName,
1196 final DataSchemaNode schemaNode, final GeneratedTypeBuilder
1198 final GeneratedTypeBuilder genTypeBuilder, final List<QName>
1199 listKeys, final Module module,
1200 final TypeProvider typeProvider, final SchemaContext
1201 schemaContext, final Map<Module, ModuleContext> genCtx,
1202 final Map<String, Map<String, GeneratedTypeBuilder>>
1203 genTypeBuilders, final boolean verboseClassComments,
1204 final BindingNamespaceType namespaceType) {
1205 checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
1206 checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
1208 if (schemaNode instanceof LeafSchemaNode) {
1209 final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
1210 final QName leafQName = leaf.getQName();
1211 final Type type = resolveLeafSchemaNodeAsMethod(nodeName, schemaContext, typeBuilder, genCtx, leaf, module,
1212 typeProvider, verboseClassComments);
1213 if (listKeys.contains(leafQName)) {
1214 resolveLeafSchemaNodeAsMethod(nodeName, schemaContext, genTypeBuilder, genCtx, leaf, module,
1215 typeProvider, verboseClassComments);
1218 if (schemaNode instanceof LeafListSchemaNode) {
1219 resolveLeafListSchemaNode(schemaContext, typeBuilder, (LeafListSchemaNode) schemaNode, module,
1220 typeProvider, genCtx, verboseClassComments);
1221 } else if (schemaNode instanceof ContainerSchemaNode) {
1222 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode,
1223 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
1224 } else if (schemaNode instanceof ListSchemaNode) {
1225 listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode,
1226 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
1227 } else if (schemaNode instanceof ChoiceSchemaNode) {
1228 choiceToGenType(module, schemaContext, verboseClassComments, basePackageName, typeBuilder, typeBuilder,
1229 (ChoiceSchemaNode) schemaNode, genTypeBuilders, genCtx, typeProvider, namespaceType);
1234 private static boolean resolveLeafSchemaNodeAsProperty(final String nodeName, final SchemaContext schemaContext,
1236 typeProvider, final Map<Module, ModuleContext>
1237 genCtx, final GeneratedTOBuilder
1238 toBuilder, final LeafSchemaNode leaf, final
1239 boolean isReadOnly, final Module module) {
1241 if (leaf != null && toBuilder != null) {
1243 final TypeDefinition<?> typeDef = leaf.getType();
1244 if (typeDef instanceof UnionTypeDefinition) {
1245 // GeneratedType for this type definition should be already
1247 final QName qname = typeDef.getQName();
1248 final Module unionModule = schemaContext.findModule(qname.getModule()).get();
1249 final ModuleContext mc = genCtx.get(unionModule);
1250 returnType = mc.getTypedefs().get(typeDef.getPath());
1251 } else if (typeDef instanceof EnumTypeDefinition && typeDef.getBaseType() == null) {
1252 // Annonymous enumeration (already generated, since it is inherited via uses).
1253 LeafSchemaNode originalLeaf = (LeafSchemaNode) SchemaNodeUtils.getRootOriginalIfPossible(leaf);
1254 QName qname = originalLeaf.getQName();
1255 final Module enumModule = schemaContext.findModule(qname.getModule()).orElse(null);
1256 returnType = genCtx.get(enumModule).getInnerType(originalLeaf.getType().getPath());
1258 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, genCtx.get(module));
1260 return AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(nodeName, toBuilder, leaf, returnType, isReadOnly);
1265 private static TypeDefinition<?> getBaseOrDeclaredType(final TypeDefinition<?> typeDef) {
1266 final TypeDefinition<?> baseType = typeDef.getBaseType();
1267 return baseType != null && baseType.getBaseType() != null ? baseType : typeDef;
1270 @SuppressWarnings({"rawtypes", "unchecked"})
1271 private static GeneratedTypeBuilder processDataSchemaNode(final Module module, final String basePackageName,
1272 final GeneratedTypeBuilder childOf, final
1273 DataSchemaNode node, final SchemaContext
1275 final boolean verboseClassComments, final Map<Module,
1276 ModuleContext> genCtx, final Map<String, Map<String,
1277 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider, final BindingNamespaceType
1280 final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(basePackageName, node, childOf, module,
1281 genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
1282 annotateDeprecatedIfNecessary(node.getStatus(), genType);
1283 genType.setModuleName(module.getName());
1284 if (verboseClassComments) {
1285 YangSourceDefinition.of(module, node).ifPresent(genType::setYangSourceDefinition);
1286 TypeComments.description(node).ifPresent(genType::addComment);
1287 node.getDescription().ifPresent(genType::setDescription);
1288 node.getReference().ifPresent(genType::setReference);
1290 genType.setSchemaPath((List) node.getPath().getPathFromRoot());
1291 if (BindingNamespaceType.isData(namespaceType)) {
1292 genType.setParentTypeForBuilder(childOf);
1295 if (node instanceof DataNodeContainer) {
1296 genCtx.get(module).addChildNodeType(node, genType);
1302 * Converts all <b>groupings</b> of the module to the list of
1303 * <code>Type</code> objects. Firstly are groupings sorted according mutual
1304 * dependencies. At least dependent (independent) groupings are in the list
1305 * saved at first positions. For every grouping the record is added to map
1306 * {@link ModuleContext#groupings allGroupings}
1308 * @param module current module
1309 * @param groupings collection of groupings from which types will be generated
1310 * @param typeProvider provider that defines contract for generated types
1311 * @param schemaContext schema context
1312 * @param genCtx map of generated entities in context of YANG modules
1313 * @param genTypeBuilders map of generated type builders
1314 * @param verboseClassComments generate verbose comments
1316 static Map<Module, ModuleContext> groupingsToGenTypes(final Module module, final Collection<GroupingDefinition>
1317 groupings, Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
1318 verboseClassComments, final Map<String, Map<String,
1319 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
1320 final String basePackageName = BindingMapping.getRootPackageName(module);
1321 final List<GroupingDefinition> groupingsSortedByDependencies = new GroupingDefinitionDependencySort()
1323 for (final GroupingDefinition grouping : groupingsSortedByDependencies) {
1324 genCtx = groupingToGenType(basePackageName, grouping, module, genCtx, schemaContext,
1325 verboseClassComments, genTypeBuilders, typeProvider);
1331 * Converts individual grouping to GeneratedType. Firstly generated type
1332 * builder is created and every child node of grouping is resolved to the
1335 * @param basePackageName string contains the module package name
1336 * @param grouping GroupingDefinition which contains data about grouping
1337 * @param module current module
1338 * @param typeProvider provider that defines contract for generated types
1339 * @param schemaContext schema context
1340 * @param genCtx map of generated entities in context of YANG modules
1341 * @param genTypeBuilders map of generated type builders
1342 * @param verboseClassComments generate verbose comments
1343 * @return GeneratedType which is generated from grouping (object of type
1344 * <code>GroupingDefinition</code>)
1346 private static Map<Module, ModuleContext> groupingToGenType(final String basePackageName,
1347 final GroupingDefinition grouping, final Module module, Map<Module, ModuleContext> genCtx,
1348 final SchemaContext schemaContext, final boolean verboseClassComments,
1349 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
1350 final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(basePackageName, grouping, null, module,
1352 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Grouping);
1353 annotateDeprecatedIfNecessary(grouping.getStatus(), genType);
1354 genCtx.get(module).addGroupingType(grouping, genType);
1355 resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes(), genCtx,
1356 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Grouping);
1357 genCtx = processUsesImplements(grouping, module, schemaContext, genCtx, BindingNamespaceType.Grouping);
1362 * //TODO: add information about multiple base identities in YANG 1.1
1363 * Converts the <b>identity</b> object to GeneratedType. Firstly it is
1364 * created transport object builder. If identity contains base identity then
1365 * reference to base identity is added to superior identity as its extend.
1366 * If identity doesn't contain base identity then only reference to abstract
1367 * class {@link org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
1368 * BaseIdentity} is added
1370 * @param module current module
1371 * @param basePackageName string contains the module package name
1372 * @param identity IdentitySchemaNode which contains data about identity
1373 * @param schemaContext SchemaContext which is used to get package and name
1374 * information about base of identity
1375 * @param genCtx generated context
1376 * @return returns generated context
1378 static Map<Module, ModuleContext> identityToGenType(final Module module, final String basePackageName,
1379 final IdentitySchemaNode identity, final SchemaContext
1380 schemaContext, final Map<Module, ModuleContext> genCtx,
1381 final boolean verboseClassComments) {
1383 resolveIdentitySchemaNode(basePackageName, schemaContext, identity, module, verboseClassComments, genCtx);
1387 private static GeneratedTypeBuilder resolveIdentitySchemaNode(final String basePackageName, final SchemaContext
1389 final IdentitySchemaNode identity, final Module
1390 module, final boolean verboseClassComments,
1391 final Map<Module, ModuleContext> genCtx) {
1392 requireNonNull(identity, "Identity can not be null!");
1394 //check first if identity has been resolved as base identity of some other one
1395 GeneratedTypeBuilder newType = findIdentityByQname(identity.getQName(), genCtx);
1396 if (newType == null) {
1397 final Module parentModule = SchemaContextUtil.findParentModule(schemaContext, identity);
1398 Preconditions.checkState(module.equals(parentModule),
1399 "If the type is null ,it must be in the same module, otherwise it must has been"
1400 + "resolved by an imported module.");
1402 final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, identity
1404 BindingNamespaceType.Identity);
1405 newType = new GeneratedTypeBuilderImpl(packageName, identity.getQName().getLocalName(), true, false,
1406 genCtx.get(module));
1408 final Set<IdentitySchemaNode> baseIdentities = identity.getBaseIdentities();
1409 if (baseIdentities.size() == 0) {
1410 //no base - abstract
1411 final GeneratedTypeBuilderImpl genType = new GeneratedTypeBuilderImpl(BaseIdentity.class.getPackage()
1413 BaseIdentity.class.getSimpleName(), genCtx.get(module));
1414 newType.addImplementsType(genType.toInstance());
1416 //multiple bases - inheritance
1417 for (IdentitySchemaNode baseIdentity : baseIdentities) {
1418 GeneratedTypeBuilder baseType = resolveIdentitySchemaNode(basePackageName, schemaContext,
1419 baseIdentity, module, verboseClassComments, genCtx);
1420 newType.addImplementsType(baseType.toInstance());
1424 if (verboseClassComments) {
1425 YangSourceDefinition.of(module).ifPresent(newType::setYangSourceDefinition);
1426 TypeComments.description(module).ifPresent(newType::addComment);
1427 module.getDescription().ifPresent(newType::setDescription);
1428 module.getReference().ifPresent(newType::setReference);
1430 newType.setSchemaPath((List) identity.getPath().getPathFromRoot());
1432 qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, identity.getQName());
1434 genCtx.get(module).addIdentityType(identity.getQName(), newType);