2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
\r
4 * This program and the accompanying materials are made available under the
\r
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
\r
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
\r
8 package org.opendaylight.yangtools.sal.binding.generator.impl;
10 import java.util.ArrayList;
11 import java.util.Collections;
12 import java.util.HashMap;
13 import java.util.List;
16 import org.opendaylight.yangtools.binding.generator.util.BindingTypes;
17 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
18 import org.opendaylight.yangtools.binding.generator.util.Types;
19 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
20 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
21 import org.opendaylight.yangtools.sal.binding.generator.api.BindingGenerator;
22 import org.opendaylight.yangtools.sal.binding.generator.spi.TypeProvider;
23 import org.opendaylight.yangtools.sal.binding.model.api.AccessModifier;
24 import org.opendaylight.yangtools.sal.binding.model.api.Type;
25 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.EnumBuilder;
26 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
27 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
28 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSignatureBuilder;
29 import org.opendaylight.yangtools.sal.binding.yang.types.GroupingDefinitionDependencySort;
30 import org.opendaylight.yangtools.sal.binding.yang.types.TypeProviderImpl;
31 import org.opendaylight.yangtools.yang.binding.RpcService;
32 import org.opendaylight.yangtools.yang.common.RpcResult;
33 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
34 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
35 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
36 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
38 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
40 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.Module;
45 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
46 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
47 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
49 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
50 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
52 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
53 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
54 import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
55 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
56 import org.opendaylight.yangtools.yang.model.util.UnionType;
57 import static com.google.common.base.Preconditions.*;
58 import static extension org.opendaylight.yangtools.binding.generator.util.Types.*;
59 import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.*;
60 import static org.opendaylight.yangtools.binding.generator.util.BindingTypes.*;
61 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.*;
62 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort
63 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
64 import org.opendaylight.yangtools.yang.model.api.UsesNode
65 import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext
66 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.AnnotationTypeBuilder
67 import org.opendaylight.yangtools.yang.model.api.ModuleImport
68 import org.opendaylight.yangtools.yang.binding.DataContainer
69 import java.util.Iterator
70 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
71 import java.util.Collection
72 import org.opendaylight.yangtools.yang.model.api.YangNode
73 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
74 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
75 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
76 import org.opendaylight.yangtools.yang.common.QName
\r
78 public class BindingGeneratorImpl implements BindingGenerator {
80 private final Map<Module, ModuleContext> genCtx = new HashMap()
83 * Outter key represents the package name. Outter value represents map of
\r
84 * all builders in the same package. Inner key represents the schema node
\r
85 * name (in JAVA class/interface name format). Inner value represents
\r
86 * instance of builder for schema node specified in key part.
\r
88 private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
91 * Provide methods for converting YANG types to JAVA types.
\r
93 private var TypeProvider typeProvider;
96 * Holds reference to schema context to resolve data of augmented elemnt
\r
97 * when creating augmentation builder
\r
99 private var SchemaContext schemaContext;
102 * Constant with the concrete name of namespace.
\r
104 private val static String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
107 * Constant with the concrete name of identifier.
\r
109 private val static String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
112 * Resolves generated types from <code>context</code> schema nodes of all
\r
115 * Generated types are created for modules, groupings, types, containers,
\r
116 * lists, choices, augments, rpcs, notification, identities.
\r
119 * schema context which contains data about all schema nodes
\r
121 * @return list of types (usually <code>GeneratedType</code>
\r
122 * <code>GeneratedTransferObject</code>which are generated from
\r
123 * <code>context</code> data.
\r
124 * @throws IllegalArgumentException
\r
125 * if param <code>context</code> is null
\r
126 * @throws IllegalStateException
\r
127 * if <code>context</code> contain no modules
\r
129 override generateTypes(SchemaContext context) {
130 checkArgument(context !== null, "Schema Context reference cannot be NULL.");
131 checkState(context.modules !== null, "Schema Context does not contain defined modules.");
132 schemaContext = context;
133 typeProvider = new TypeProviderImpl(context);
134 val Set<Module> modules = context.modules;
135 return generateTypes(context, modules);
139 * Resolves generated types from <code>context</code> schema nodes only for
\r
140 * modules specified in <code>modules</code>
\r
142 * Generated types are created for modules, groupings, types, containers,
\r
143 * lists, choices, augments, rpcs, notification, identities.
\r
146 * schema context which contains data about all schema nodes
\r
149 * set of modules for which schema nodes should be generated
\r
151 * @return list of types (usually <code>GeneratedType</code> or
\r
152 * <code>GeneratedTransferObject</code>) which:
\r
154 * <li>are generated from <code>context</code> schema nodes and</li>
\r
155 * <li>are also part of some of the module in <code>modules</code>
\r
158 * @throws IllegalArgumentException
\r
160 * <li>if param <code>context</code> is null or</li>
\r
161 * <li>if param <code>modules</code> is null</li>
\r
163 * @throws IllegalStateException
\r
164 * if <code>context</code> contain no modules
\r
166 override generateTypes(SchemaContext context, Set<Module> modules) {
167 checkArgument(context !== null, "Schema Context reference cannot be NULL.");
168 checkState(context.modules !== null, "Schema Context does not contain defined modules.");
169 checkArgument(modules !== null, "Set of Modules cannot be NULL.");
171 schemaContext = context;
172 typeProvider = new TypeProviderImpl(context);
173 val contextModules = ModuleDependencySort.sort(context.modules);
174 genTypeBuilders = new HashMap();
176 for (contextModule : contextModules) {
177 moduleToGenTypes(contextModule, context);
179 for (contextModule : contextModules) {
180 allAugmentsToGenTypes(contextModule);
183 val List<Type> filteredGenTypes = new ArrayList();
184 for (Module m : modules) {
185 filteredGenTypes.addAll(genCtx.get(m).generatedTypes);
190 return filteredGenTypes;
193 private def void moduleToGenTypes(Module m, SchemaContext context) {
194 genCtx.put(m, new ModuleContext)
195 allTypeDefinitionsToGenTypes(m)
196 groupingsToGenTypes(m, m.groupings)
197 rpcMethodsToGenType(m)
198 allIdentitiesToGenTypes(m, context)
199 notificationsToGenType(m)
201 if (!m.childNodes.isEmpty()) {
202 val moduleType = moduleToDataType(m)
203 genCtx.get(m).addModuleNode(moduleType)
204 val basePackageName = moduleNamespaceToPackageName(m);
205 resolveDataSchemaNodes(m, basePackageName, moduleType, moduleType, m.childNodes)
210 * Converts all extended type definitions of module to the list of
\r
211 * <code>Type</code> objects.
\r
214 * module from which is obtained set of type definitions
\r
215 * @throws IllegalArgumentException
\r
217 * <li>if module equals null</li>
\r
218 * <li>if name of module equals null</li>
\r
219 * <li>if type definitions of module equal null</li>
\r
223 private def void allTypeDefinitionsToGenTypes(Module module) {
224 checkArgument(module !== null, "Module reference cannot be NULL.");
225 checkArgument(module.name !== null, "Module name cannot be NULL.");
226 val it = new DataNodeIterator(module);
227 val List<TypeDefinition<?>> typeDefinitions = it.allTypedefs;
228 checkState(typeDefinitions !== null, '''Type Definitions for module «module.name» cannot be NULL.''');
230 for (TypeDefinition<?> typedef : typeDefinitions) {
231 if (typedef !== null) {
232 val type = (typeProvider as TypeProviderImpl).generatedTypeForExtendedDefinitionType(typedef, typedef);
234 genCtx.get(module).addTypedefType(typedef.path, type)
240 private def void containerToGenType(Module module, String basePackageName, GeneratedTypeBuilder parent,
241 GeneratedTypeBuilder childOf, ContainerSchemaNode node) {
242 if (node.augmenting || node.addedByUses) {
245 val packageName = packageNameForGeneratedType(basePackageName, node.path)
246 val genType = addDefaultInterfaceDefinition(packageName, node, childOf)
247 constructGetter(parent, node.QName.localName, node.description, genType)
248 genCtx.get(module).addChildNodeType(node.path, genType)
249 resolveDataSchemaNodes(module, basePackageName, genType, genType, node.childNodes)
250 groupingsToGenTypes(module, node.groupings)
251 processUsesAugments(node, module)
254 private def void listToGenType(Module module, String basePackageName, GeneratedTypeBuilder parent,
255 GeneratedTypeBuilder childOf, ListSchemaNode node) {
256 if (node.augmenting || node.addedByUses) {
259 val packageName = packageNameForGeneratedType(basePackageName, (node).path)
260 val genType = addDefaultInterfaceDefinition(packageName, node, childOf)
261 constructGetter(parent, node.QName.localName, node.description, Types.listTypeFor(genType))
262 genCtx.get(module).addChildNodeType(node.path, genType)
263 groupingsToGenTypes(module, node.groupings)
264 processUsesAugments(node, module)
266 val List<String> listKeys = listKeys(node);
267 val genTOBuilder = resolveListKeyTOBuilder(packageName, node);
269 if (genTOBuilder !== null) {
270 val identifierMarker = IDENTIFIER.parameterizedTypeFor(genType);
271 val identifiableMarker = IDENTIFIABLE.parameterizedTypeFor(genTOBuilder);
272 genTOBuilder.addImplementsType(identifierMarker);
273 genType.addImplementsType(identifiableMarker);
276 for (schemaNode : node.childNodes) {
277 if (!schemaNode.augmenting) {
278 addSchemaNodeToListBuilders(basePackageName, schemaNode, genType, genTOBuilder, listKeys, module);
282 typeBuildersToGenTypes(module, genType, genTOBuilder);
285 private def void processUsesAugments(DataNodeContainer node, Module module) {
286 val basePackageName = moduleNamespaceToPackageName(module);
287 for (usesNode : node.uses) {
288 for (augment : usesNode.augmentations) {
289 augmentationToGenTypes(basePackageName, augment, module, usesNode);
290 processUsesAugments(augment, module);
296 * Converts all <b>augmentation</b> of the module to the list
\r
297 * <code>Type</code> objects.
\r
300 * module from which is obtained list of all augmentation objects
\r
301 * to iterate over them
\r
302 * @throws IllegalArgumentException
\r
304 * <li>if the module equals null</li>
\r
305 * <li>if the name of module equals null</li>
\r
306 * <li>if the set of child nodes equals null</li>
\r
310 private def void allAugmentsToGenTypes(Module module) {
311 checkArgument(module !== null, "Module reference cannot be NULL.");
312 checkArgument(module.name !== null, "Module name cannot be NULL.");
313 if (module.childNodes === null) {
314 throw new IllegalArgumentException(
315 "Reference to Set of Augmentation Definitions in module " + module.name + " cannot be NULL.");
318 val basePackageName = moduleNamespaceToPackageName(module);
319 val List<AugmentationSchema> augmentations = resolveAugmentations(module);
320 for (augment : augmentations) {
321 augmentationToGenTypes(basePackageName, augment, module, null);
326 * Returns list of <code>AugmentationSchema</code> objects. The objects are
\r
327 * sorted according to the length of their target path from the shortest to
\r
331 * module from which is obtained list of all augmentation objects
\r
332 * @return list of sorted <code>AugmentationSchema</code> objects obtained
\r
333 * from <code>module</code>
\r
334 * @throws IllegalArgumentException
\r
336 * <li>if the module equals null</li>
\r
337 * <li>if the set of augmentation equals null</li>
\r
341 private def List<AugmentationSchema> resolveAugmentations(Module module) {
342 checkArgument(module !== null, "Module reference cannot be NULL.");
343 checkState(module.augmentations !== null, "Augmentations Set cannot be NULL.");
345 val Set<AugmentationSchema> augmentations = module.augmentations;
346 val List<AugmentationSchema> sortedAugmentations = new ArrayList(augmentations);
347 Collections.sort(sortedAugmentations,
348 [ augSchema1, augSchema2 |
349 if (augSchema1.targetPath.path.size() > augSchema2.targetPath.path.size()) {
351 } else if (augSchema1.targetPath.path.size() < augSchema2.targetPath.path.size()) {
356 return sortedAugmentations;
360 * Converts whole <b>module</b> to <code>GeneratedType</code> object.
\r
361 * Firstly is created the module builder object from which is vally
\r
362 * obtained reference to <code>GeneratedType</code> object.
\r
365 * module from which are obtained the module name, child nodes,
\r
366 * uses and is derived package name
\r
367 * @return <code>GeneratedType</code> which is internal representation of
\r
369 * @throws IllegalArgumentException
\r
370 * if the module equals null
\r
373 private def GeneratedTypeBuilder moduleToDataType(Module module) {
374 checkArgument(module !== null, "Module reference cannot be NULL.");
376 val moduleDataTypeBuilder = moduleTypeBuilder(module, "Data");
377 addImplementedInterfaceFromUses(module, moduleDataTypeBuilder);
378 moduleDataTypeBuilder.addImplementsType(DATA_ROOT);
379 return moduleDataTypeBuilder;
383 * Converts all <b>rpcs</b> inputs and outputs substatements of the module
\r
384 * to the list of <code>Type</code> objects. In addition are to containers
\r
385 * and lists which belong to input or output also part of returning list.
\r
388 * module from which is obtained set of all rpc objects to
\r
389 * iterate over them
\r
390 * @throws IllegalArgumentException
\r
392 * <li>if the module equals null</li>
\r
393 * <li>if the name of module equals null</li>
\r
394 * <li>if the set of child nodes equals null</li>
\r
398 private def void rpcMethodsToGenType(Module module) {
399 checkArgument(module !== null, "Module reference cannot be NULL.");
400 checkArgument(module.name !== null, "Module name cannot be NULL.");
401 checkArgument(module.childNodes !== null,
402 "Reference to Set of RPC Method Definitions in module " + module.name + " cannot be NULL.");
404 val basePackageName = moduleNamespaceToPackageName(module);
405 val Set<RpcDefinition> rpcDefinitions = module.rpcs;
406 if (rpcDefinitions.isEmpty()) {
410 val interfaceBuilder = moduleTypeBuilder(module, "Service");
411 interfaceBuilder.addImplementsType(Types.typeForClass(RpcService));
412 for (rpc : rpcDefinitions) {
414 val rpcName = parseToClassName(rpc.QName.localName);
415 val rpcMethodName = parseToValidParamName(rpcName);
416 val method = interfaceBuilder.addMethod(rpcMethodName);
417 val input = rpc.input;
418 val output = rpc.output;
420 if (input !== null) {
421 val inType = addRawInterfaceDefinition(basePackageName, input, rpcName);
422 addImplementedInterfaceFromUses(input, inType);
423 inType.addImplementsType(DATA_OBJECT);
424 inType.addImplementsType(augmentable(inType));
425 resolveDataSchemaNodes(module, basePackageName, inType, inType, input.childNodes);
426 genCtx.get(module).addChildNodeType(input.path, inType)
427 val inTypeInstance = inType.toInstance();
428 method.addParameter(inTypeInstance, "input");
431 var Type outTypeInstance = VOID;
432 if (output !== null) {
433 val outType = addRawInterfaceDefinition(basePackageName, output, rpcName);
434 addImplementedInterfaceFromUses(output, outType);
435 outType.addImplementsType(DATA_OBJECT);
436 outType.addImplementsType(augmentable(outType));
437 resolveDataSchemaNodes(module, basePackageName, outType, outType, output.childNodes);
438 genCtx.get(module).addChildNodeType(output.path, outType)
439 outTypeInstance = outType.toInstance();
442 val rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult), outTypeInstance);
443 method.setReturnType(Types.parameterizedTypeFor(FUTURE, rpcRes));
447 genCtx.get(module).addTopLevelNodeType(interfaceBuilder)
451 * Converts all <b>notifications</b> of the module to the list of
\r
452 * <code>Type</code> objects. In addition are to this list added containers
\r
453 * and lists which are part of this notification.
\r
456 * module from which is obtained set of all notification objects
\r
457 * to iterate over them
\r
458 * @throws IllegalArgumentException
\r
460 * <li>if the module equals null</li>
\r
461 * <li>if the name of module equals null</li>
\r
462 * <li>if the set of child nodes equals null</li>
\r
466 private def void notificationsToGenType(Module module) {
467 checkArgument(module !== null, "Module reference cannot be NULL.");
468 checkArgument(module.name !== null, "Module name cannot be NULL.");
470 if (module.childNodes === null) {
471 throw new IllegalArgumentException(
472 "Reference to Set of Notification Definitions in module " + module.name + " cannot be NULL.");
474 val notifications = module.notifications;
475 if(notifications.empty) return;
477 val listenerInterface = moduleTypeBuilder(module, "Listener");
478 listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER);
479 val basePackageName = moduleNamespaceToPackageName(module);
481 for (notification : notifications) {
482 if (notification !== null) {
483 processUsesAugments(notification, module);
485 val notificationInterface = addDefaultInterfaceDefinition(basePackageName, notification,
486 BindingTypes.DATA_OBJECT);
487 notificationInterface.addImplementsType(NOTIFICATION);
488 genCtx.get(module).addChildNodeType(notification.path, notificationInterface)
490 // Notification object
\r
491 resolveDataSchemaNodes(module, basePackageName, notificationInterface, notificationInterface,
492 notification.childNodes);
494 listenerInterface.addMethod("on" + notificationInterface.name) //
\r
495 .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification").
496 setReturnType(Types.VOID);
500 genCtx.get(module).addTopLevelNodeType(listenerInterface)
504 * Converts all <b>identities</b> of the module to the list of
\r
505 * <code>Type</code> objects.
\r
508 * module from which is obtained set of all identity objects to
\r
509 * iterate over them
\r
511 * schema context only used as input parameter for method
\r
512 * {@link identityToGenType}
\r
515 private def void allIdentitiesToGenTypes(Module module, SchemaContext context) {
516 val Set<IdentitySchemaNode> schemaIdentities = module.identities;
517 val basePackageName = moduleNamespaceToPackageName(module);
519 if (schemaIdentities !== null && !schemaIdentities.isEmpty()) {
520 for (identity : schemaIdentities) {
521 identityToGenType(module, basePackageName, identity, context);
527 * Converts the <b>identity</b> object to GeneratedType. Firstly it is
\r
528 * created transport object builder. If identity contains base identity then
\r
529 * reference to base identity is added to superior identity as its extend.
\r
530 * If identity doesn't contain base identity then only reference to abstract
\r
531 * class {@link org.opendaylight.yangtools.yang.model.api.BaseIdentity
\r
532 * BaseIdentity} is added
\r
534 * @param module current module
\r
535 * @param basePackageName
\r
536 * string contains the module package name
\r
538 * IdentitySchemaNode which contains data about identity
\r
540 * SchemaContext which is used to get package and name
\r
541 * information about base of identity
\r
544 private def void identityToGenType(Module module, String basePackageName, IdentitySchemaNode identity,
545 SchemaContext context) {
546 if (identity === null) {
549 val packageName = packageNameForGeneratedType(basePackageName, identity.path);
550 val genTypeName = parseToClassName(identity.QName.localName);
551 val newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
552 val baseIdentity = identity.baseIdentity;
553 if (baseIdentity === null) {
554 newType.setExtendsType(Types.baseIdentityTO);
556 val baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
557 val returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule);
558 val returnTypeName = parseToClassName(baseIdentity.QName.localName);
559 val gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName).toInstance();
560 newType.setExtendsType(gto);
562 newType.setAbstract(true);
563 genCtx.get(module).addIdentityType(newType)
567 * Converts all <b>groupings</b> of the module to the list of
\r
568 * <code>Type</code> objects. Firstly are groupings sorted according mutual
\r
569 * dependencies. At least dependend (indepedent) groupings are in the list
\r
570 * saved at first positions. For every grouping the record is added to map
\r
571 * {@link BindingGeneratorImpl#allGroupings allGroupings}
\r
575 * @param collection of groupings from which types will be generated
\r
578 private def void groupingsToGenTypes(Module module, Collection<GroupingDefinition> groupings) {
579 val basePackageName = moduleNamespaceToPackageName(module);
580 val List<GroupingDefinition> groupingsSortedByDependencies = new GroupingDefinitionDependencySort().sort(
582 for (grouping : groupingsSortedByDependencies) {
583 groupingToGenType(basePackageName, grouping, module);
588 * Converts individual grouping to GeneratedType. Firstly generated type
\r
589 * builder is created and every child node of grouping is resolved to the
\r
592 * @param basePackageName
\r
593 * string contains the module package name
\r
595 * GroupingDefinition which contains data about grouping
\r
596 * @param module current module
\r
597 * @return GeneratedType which is generated from grouping (object of type
\r
598 * <code>GroupingDefinition</code>)
\r
600 private def void groupingToGenType(String basePackageName, GroupingDefinition grouping, Module module) {
601 val packageName = packageNameForGeneratedType(basePackageName, grouping.path);
602 val genType = addDefaultInterfaceDefinition(packageName, grouping);
603 genCtx.get(module).addGroupingType(grouping.path, genType)
604 resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.childNodes);
605 groupingsToGenTypes(module, grouping.groupings);
606 processUsesAugments(grouping, module);
610 * Tries to find EnumTypeDefinition in <code>typeDefinition</code>. If base
\r
611 * type of <code>typeDefinition</code> is of the type ExtendedType then this
\r
612 * method is recursivelly called with this base type.
\r
614 * @param typeDefinition
\r
615 * TypeDefinition in which should be EnumTypeDefinition found as
\r
617 * @return EnumTypeDefinition if it is found inside
\r
618 * <code>typeDefinition</code> or <code>null</code> in other case
\r
620 private def EnumTypeDefinition enumTypeDefFromExtendedType(TypeDefinition<?> typeDefinition) {
621 if (typeDefinition !== null) {
622 if (typeDefinition.baseType instanceof EnumTypeDefinition) {
623 return typeDefinition.baseType as EnumTypeDefinition;
624 } else if (typeDefinition.baseType instanceof ExtendedType) {
625 return enumTypeDefFromExtendedType(typeDefinition.baseType);
632 * Adds enumeration builder created from <code>enumTypeDef</code> to
\r
633 * <code>typeBuilder</code>.
\r
635 * Each <code>enumTypeDef</code> item is added to builder with its name and
\r
638 * @param enumTypeDef
\r
639 * EnumTypeDefinition contains enum data
\r
641 * string contains name which will be assigned to enumeration
\r
643 * @param typeBuilder
\r
644 * GeneratedTypeBuilder to which will be enum builder assigned
\r
645 * @return enumeration builder which contais data from
\r
646 * <code>enumTypeDef</code>
\r
648 private def EnumBuilder resolveInnerEnumFromTypeDefinition(EnumTypeDefinition enumTypeDef, String enumName,
649 GeneratedTypeBuilder typeBuilder) {
650 if ((enumTypeDef !== null) && (typeBuilder !== null) && (enumTypeDef.QName !== null) &&
651 (enumTypeDef.QName.localName !== null)) {
652 val enumerationName = parseToClassName(enumName);
653 val enumBuilder = typeBuilder.addEnumeration(enumerationName);
654 enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
661 * Generates type builder for <code>module</code>.
\r
664 * Module which is source of package name for generated type
\r
667 * string which is added to the module class name representation
\r
669 * @return instance of GeneratedTypeBuilder which represents
\r
670 * <code>module</code>.
\r
671 * @throws IllegalArgumentException
\r
672 * if <code>module</code> equals null
\r
674 private def GeneratedTypeBuilder moduleTypeBuilder(Module module, String postfix) {
675 checkArgument(module !== null, "Module reference cannot be NULL.");
676 val packageName = moduleNamespaceToPackageName(module);
677 val moduleName = parseToClassName(module.name) + postfix;
678 return new GeneratedTypeBuilderImpl(packageName, moduleName);
682 * Converts <code>augSchema</code> to list of <code>Type</code> which
\r
683 * contains generated type for augmentation. In addition there are also
\r
684 * generated types for all containers, list and choices which are child of
\r
685 * <code>augSchema</code> node or a generated types for cases are added if
\r
686 * augmented node is choice.
\r
688 * @param augmentPackageName
\r
689 * string with the name of the package to which the augmentation
\r
692 * AugmentationSchema which is contains data about agumentation
\r
693 * (target path, childs...)
\r
694 * @param module current module
\r
695 * @param parentUsesNode parent uses node of this augment (can be null if this augment is not defined under uses statement)
\r
696 * @throws IllegalArgumentException
\r
698 * <li>if <code>augmentPackageName</code> equals null</li>
\r
699 * <li>if <code>augSchema</code> equals null</li>
\r
700 * <li>if target path of <code>augSchema</code> equals null</li>
\r
703 private def void augmentationToGenTypes(String augmentPackageName, AugmentationSchema augSchema, Module module,
704 UsesNode parentUsesNode) {
705 checkArgument(augmentPackageName !== null, "Package Name cannot be NULL.");
706 checkArgument(augSchema !== null, "Augmentation Schema cannot be NULL.");
707 checkState(augSchema.targetPath !== null,
708 "Augmentation Schema does not contain Target Path (Target Path is NULL).");
710 processUsesAugments(augSchema, module);
712 // EVERY augmented interface will extends Augmentation<T> interface
\r
713 // and DataObject interface
\r
714 val targetPath = augSchema.targetPath;
715 var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
716 if (targetSchemaNode instanceof DataSchemaNode && (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
717 if (parentUsesNode == null) {
718 targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
720 targetSchemaNode = findOriginalTargetFromGrouping(targetSchemaNode.QName.localName, parentUsesNode);
722 if (targetSchemaNode == null) {
723 throw new NullPointerException(
724 "Failed to find target node from grouping for augmentation " + augSchema + " in module " +
729 if (targetSchemaNode !== null) {
730 var targetTypeBuilder = findChildNodeByPath(targetSchemaNode.path)
731 if (targetTypeBuilder === null) {
732 targetTypeBuilder = findCaseByPath(targetSchemaNode.path)
734 if (targetTypeBuilder === null) {
735 throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
737 if (!(targetSchemaNode instanceof ChoiceNode)) {
738 var packageName = augmentPackageName;
739 if (parentUsesNode != null) {
740 packageName = packageNameForGeneratedType(augmentPackageName, augSchema.targetPath);
742 val augTypeBuilder = addRawAugmentGenTypeDefinition(module, packageName, augmentPackageName,
743 targetTypeBuilder.toInstance, augSchema);
744 genCtx.get(module).addAugmentType(augTypeBuilder)
746 generateTypesFromAugmentedChoiceCases(module, augmentPackageName, targetTypeBuilder.toInstance,
747 targetSchemaNode as ChoiceNode, augSchema.childNodes);
753 * Utility method which search for original node defined in grouping.
\r
755 private def DataSchemaNode findOriginal(DataSchemaNode node) {
756 var DataSchemaNode result = findCorrectTargetFromGrouping(node);
757 if (result == null) {
758 result = findCorrectTargetFromAugment(node);
759 if (result != null) {
760 if (result.addedByUses) {
761 result = findOriginal(result);
768 private def DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node) {
769 if (!node.augmenting) {
773 var String currentName = node.QName.localName;
774 var tmpPath = new ArrayList<String>();
775 var YangNode parent = node;
776 var AugmentationSchema augment = null;
778 parent = (parent as DataSchemaNode).parent;
779 if (parent instanceof AugmentationTarget) {
780 tmpPath.add(currentName);
781 augment = findNodeInAugment((parent as AugmentationTarget).availableAugmentations, currentName);
782 if (augment == null) {
783 currentName = (parent as DataSchemaNode).QName.localName;
786 } while ((parent as DataSchemaNode).augmenting && augment == null);
788 if (augment == null) {
791 Collections.reverse(tmpPath);
792 var Object actualParent = augment;
793 var DataSchemaNode result = null;
794 for (name : tmpPath) {
795 if (actualParent instanceof DataNodeContainer) {
796 result = (actualParent as DataNodeContainer).getDataChildByName(name);
797 actualParent = (actualParent as DataNodeContainer).getDataChildByName(name);
799 if (actualParent instanceof ChoiceNode) {
800 result = (actualParent as ChoiceNode).getCaseNodeByName(name);
801 actualParent = (actualParent as ChoiceNode).getCaseNodeByName(name);
806 if (result.addedByUses) {
807 result = findCorrectTargetFromGrouping(result);
814 private def AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, String name) {
815 for (augment : augments) {
816 if (augment.getDataChildByName(name) != null) {
823 private def DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node) {
824 if (node.path.path.size == 1) {
826 // uses is under module statement
\r
827 val Module m = findParentModule(schemaContext, node);
828 var DataSchemaNode result = null;
830 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
831 if (!(targetGrouping instanceof GroupingDefinition)) {
832 throw new IllegalArgumentException("Failed to generate code for augment in " + u);
834 var gr = targetGrouping as GroupingDefinition;
835 result = gr.getDataChildByName(node.QName.localName);
837 if (result == null) {
838 throw new IllegalArgumentException("Failed to generate code for augment");
842 var DataSchemaNode result = null;
843 var String currentName = node.QName.localName;
844 var tmpPath = new ArrayList<String>();
845 var YangNode parent = node.parent;
847 tmpPath.add(currentName);
848 val dataNodeParent = parent as DataNodeContainer;
849 for (u : dataNodeParent.uses) {
850 if (result == null) {
\r
851 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
852 if (!(targetGrouping instanceof GroupingDefinition)) {
853 throw new IllegalArgumentException("Failed to generate code for augment in " + u);
855 var gr = targetGrouping as GroupingDefinition;
856 result = gr.getDataChildByName(currentName);
\r
859 if (result == null) {
860 currentName = (parent as SchemaNode).QName.localName;
861 if (parent instanceof DataSchemaNode) {
862 parent = (parent as DataSchemaNode).parent;
864 parent = (parent as DataNodeContainer).parent;
867 } while (result == null && !(parent instanceof Module));
869 if (result != null) {
870 if (tmpPath.size == 1) {
873 var DataSchemaNode newParent = result;
874 Collections.reverse(tmpPath);
876 for (name : tmpPath) {
877 newParent = (newParent as DataNodeContainer).getDataChildByName(name);
888 * Convenient method to find node added by uses statement.
\r
890 private def DataSchemaNode findOriginalTargetFromGrouping(String targetSchemaNodeName, UsesNode parentUsesNode) {
891 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, parentUsesNode.groupingPath.path);
892 if (!(targetGrouping instanceof GroupingDefinition)) {
893 throw new IllegalArgumentException("Failed to generate code for augment in " + parentUsesNode);
896 var grouping = targetGrouping as GroupingDefinition;
897 var result = grouping.getDataChildByName(targetSchemaNodeName);
898 if (result == null) {
901 var boolean fromUses = result.addedByUses;
903 var Iterator<UsesNode> groupingUses = grouping.uses.iterator;
905 if (groupingUses.hasNext()) {
906 grouping = findNodeInSchemaContext(schemaContext, groupingUses.next().groupingPath.path) as GroupingDefinition;
907 result = grouping.getDataChildByName(targetSchemaNodeName);
908 fromUses = result.addedByUses;
910 throw new NullPointerException("Failed to generate code for augment in " + parentUsesNode);
918 * Returns a generated type builder for an augmentation.
\r
920 * The name of the type builder is equal to the name of augmented node with
\r
921 * serial number as suffix.
\r
923 * @param module current module
\r
924 * @param augmentPackageName
\r
925 * string with contains the package name to which the augment
\r
927 * @param basePackageName
\r
928 * string with the package name to which the augmented node
\r
930 * @param targetTypeRef
\r
933 * augmentation schema which contains data about the child nodes
\r
934 * and uses of augment
\r
935 * @return generated type builder for augment
\r
937 private def GeneratedTypeBuilder addRawAugmentGenTypeDefinition(Module module, String augmentPackageName,
938 String basePackageName, Type targetTypeRef, AugmentationSchema augSchema) {
939 var Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
940 if (augmentBuilders === null) {
941 augmentBuilders = new HashMap();
942 genTypeBuilders.put(augmentPackageName, augmentBuilders);
944 val augIdentifier = getAugmentIdentifier(augSchema.unknownSchemaNodes);
946 val augTypeName = if (augIdentifier !== null) {
947 parseToClassName(augIdentifier)
949 augGenTypeName(augmentBuilders, targetTypeRef.name);
952 val augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
954 augTypeBuilder.addImplementsType(DATA_OBJECT);
955 augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
956 addImplementedInterfaceFromUses(augSchema, augTypeBuilder);
958 augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema.childNodes);
959 augmentBuilders.put(augTypeName, augTypeBuilder);
960 return augTypeBuilder;
965 * @param unknownSchemaNodes
\r
966 * @return nodeParameter of UnknownSchemaNode
\r
968 private def String getAugmentIdentifier(List<UnknownSchemaNode> unknownSchemaNodes) {
969 for (unknownSchemaNode : unknownSchemaNodes) {
970 val nodeType = unknownSchemaNode.nodeType;
971 if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.localName) &&
972 YANG_EXT_NAMESPACE.equals(nodeType.namespace.toString())) {
973 return unknownSchemaNode.nodeParameter;
980 * Returns first unique name for the augment generated type builder. The
\r
981 * generated type builder name for augment consists from name of augmented
\r
982 * node and serial number of its augmentation.
\r
985 * map of builders which were created in the package to which the
\r
986 * augmentation belongs
\r
987 * @param genTypeName
\r
988 * string with name of augmented node
\r
989 * @return string with unique name for augmentation builder
\r
991 private def String augGenTypeName(Map<String, GeneratedTypeBuilder> builders, String genTypeName) {
993 while ((builders !== null) && builders.containsKey(genTypeName + index)) {
996 return genTypeName + index;
1000 * Adds the methods to <code>typeBuilder</code> which represent subnodes of
\r
1001 * node for which <code>typeBuilder</code> was created.
\r
1003 * The subnodes aren't mapped to the methods if they are part of grouping or
\r
1004 * augment (in this case are already part of them).
\r
1006 * @param module current module
\r
1007 * @param basePackageName
\r
1008 * string contains the module package name
\r
1010 * generated type builder which represents any node. The subnodes
\r
1011 * of this node are added to the <code>typeBuilder</code> as
\r
1012 * methods. The subnode can be of type leaf, leaf-list, list,
\r
1013 * container, choice.
\r
1014 * @param childOf parent type
\r
1015 * @param schemaNodes
\r
1016 * set of data schema nodes which are the children of the node
\r
1017 * for which <code>typeBuilder</code> was created
\r
1018 * @return generated type builder which is the same builder as input
\r
1019 * parameter. The getter methods (representing child nodes) could be
\r
1022 private def GeneratedTypeBuilder resolveDataSchemaNodes(Module module, String basePackageName,
1023 GeneratedTypeBuilder parent, GeneratedTypeBuilder childOf, Set<DataSchemaNode> schemaNodes) {
1024 if ((schemaNodes !== null) && (parent !== null)) {
1025 for (schemaNode : schemaNodes) {
1026 if (!schemaNode.augmenting && !schemaNode.addedByUses) {
1027 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module);
1035 * Adds the methods to <code>typeBuilder</code> what represents subnodes of
\r
1036 * node for which <code>typeBuilder</code> was created.
\r
1038 * @param module current module
\r
1039 * @param basePackageName
\r
1040 * string contains the module package name
\r
1041 * @param typeBuilder
\r
1042 * generated type builder which represents any node. The subnodes
\r
1043 * of this node are added to the <code>typeBuilder</code> as
\r
1044 * methods. The subnode can be of type leaf, leaf-list, list,
\r
1045 * container, choice.
\r
1046 * @param childOf parent type
\r
1047 * @param schemaNodes
\r
1048 * set of data schema nodes which are the children of the node
\r
1049 * for which <code>typeBuilder</code> was created
\r
1050 * @return generated type builder which is the same object as the input
\r
1051 * parameter <code>typeBuilder</code>. The getter method could be
\r
1054 private def GeneratedTypeBuilder augSchemaNodeToMethods(Module module, String basePackageName,
1055 GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Set<DataSchemaNode> schemaNodes) {
1056 if ((schemaNodes !== null) && (typeBuilder !== null)) {
1057 for (schemaNode : schemaNodes) {
1058 if (!schemaNode.isAugmenting()) {
1059 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module);
1067 * Adds to <code>typeBuilder</code> a method which is derived from
\r
1068 * <code>schemaNode</code>.
\r
1070 * @param basePackageName
\r
1071 * string with the module package name
\r
1073 * data schema node which is added to <code>typeBuilder</code> as
\r
1075 * @param typeBuilder
\r
1076 * generated type builder to which is <code>schemaNode</code>
\r
1077 * added as a method.
\r
1078 * @param childOf parent type
\r
1079 * @param module current module
\r
1081 private def void addSchemaNodeToBuilderAsMethod(String basePackageName, DataSchemaNode node,
1082 GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Module module) {
1083 if (node !== null && typeBuilder !== null) {
1085 case node instanceof LeafSchemaNode:
1086 resolveLeafSchemaNodeAsMethod(typeBuilder, node as LeafSchemaNode)
1087 case node instanceof LeafListSchemaNode:
1088 resolveLeafListSchemaNode(typeBuilder, node as LeafListSchemaNode)
1089 case node instanceof ContainerSchemaNode:
1090 containerToGenType(module, basePackageName, typeBuilder, childOf, node as ContainerSchemaNode)
1091 case node instanceof ListSchemaNode:
1092 listToGenType(module, basePackageName, typeBuilder, childOf, node as ListSchemaNode)
1093 case node instanceof ChoiceNode:
1094 choiceToGeneratedType(module, basePackageName, typeBuilder, node as ChoiceNode)
1100 * Converts <code>choiceNode</code> to the list of generated types for
\r
1101 * choice and its cases.
\r
1103 * The package names for choice and for its cases are created as
\r
1104 * concatenation of the module package (<code>basePackageName</code>) and
\r
1105 * names of all parents node.
\r
1107 * @param module current module
\r
1108 * @param basePackageName
\r
1109 * string with the module package name
\r
1110 * @param parent parent type
\r
1111 * @param childOf concrete parent for case child nodes
\r
1112 * @param choiceNode
\r
1113 * choice node which is mapped to generated type. Also child
\r
1114 * nodes - cases are mapped to generated types.
\r
1115 * @throws IllegalArgumentException
\r
1117 * <li>if <code>basePackageName</code> equals null</li>
\r
1118 * <li>if <code>choiceNode</code> equals null</li>
\r
1122 private def void choiceToGeneratedType(Module module, String basePackageName, GeneratedTypeBuilder parent,
1123 ChoiceNode choiceNode) {
1124 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1125 checkArgument(choiceNode !== null, "Choice Schema Node cannot be NULL.");
1127 val packageName = packageNameForGeneratedType(basePackageName, choiceNode.path);
1128 val choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
1129 constructGetter(parent, choiceNode.QName.localName, choiceNode.description, choiceTypeBuilder);
1130 choiceTypeBuilder.addImplementsType(DataContainer.typeForClass);
1131 genCtx.get(module).addChildNodeType(choiceNode.path, choiceTypeBuilder)
1132 generateTypesFromChoiceCases(module, basePackageName, parent, choiceTypeBuilder.toInstance, choiceNode);
1136 * Converts <code>caseNodes</code> set to list of corresponding generated
\r
1139 * For every <i>case</i> which isn't added through augment or <i>uses</i> is
\r
1140 * created generated type builder. The package names for the builder is
\r
1141 * created as concatenation of the module package (
\r
1142 * <code>basePackageName</code>) and names of all parents nodes of the
\r
1143 * concrete <i>case</i>. There is also relation "<i>implements type</i>"
\r
1144 * between every case builder and <i>choice</i> type
\r
1146 * @param basePackageName
\r
1147 * string with the module package name
\r
1148 * @param refChoiceType
\r
1149 * type which represents superior <i>case</i>
\r
1150 * @param caseNodes
\r
1151 * set of choice case nodes which are mapped to generated types
\r
1152 * @return list of generated types for <code>caseNodes</code>.
\r
1153 * @throws IllegalArgumentException
\r
1155 * <li>if <code>basePackageName</code> equals null</li>
\r
1156 * <li>if <code>refChoiceType</code> equals null</li>
\r
1157 * <li>if <code>caseNodes</code> equals null</li>
\r
1161 private def void generateTypesFromChoiceCases(Module module, String basePackageName,
1162 GeneratedTypeBuilder choiceParent, Type refChoiceType, ChoiceNode choiceNode) {
1163 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1164 checkArgument(refChoiceType !== null, "Referenced Choice Type cannot be NULL.");
1165 checkArgument(choiceNode !== null, "ChoiceNode cannot be NULL.");
1167 val Set<ChoiceCaseNode> caseNodes = choiceNode.cases;
1168 if (caseNodes == null) {
1172 for (caseNode : caseNodes) {
1173 if (caseNode !== null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
1174 val packageName = packageNameForGeneratedType(basePackageName, caseNode.path);
1175 val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
1176 caseTypeBuilder.addImplementsType(refChoiceType);
1177 genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder)
1178 val Set<DataSchemaNode> caseChildNodes = caseNode.childNodes;
1179 if (caseChildNodes !== null) {
1180 val parentNode = choiceNode.parent;
1181 var SchemaNode parent;
1182 if (parentNode instanceof AugmentationSchema) {
1183 val augSchema = parentNode as AugmentationSchema;
1184 val targetPath = augSchema.targetPath;
1185 var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
1186 if (targetSchemaNode instanceof DataSchemaNode &&
1187 (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
1188 targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
1189 if (targetSchemaNode == null) {
1190 throw new NullPointerException(
1191 "Failed to find target node from grouping for augmentation " + augSchema +
1192 " in module " + module.name);
1195 parent = targetSchemaNode as SchemaNode
1197 parent = choiceNode.parent as SchemaNode;
1199 var GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.path)
1200 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes);
1204 processUsesAugments(caseNode, module);
1209 * Generates list of generated types for all the cases of a choice which are
\r
1210 * added to the choice through the augment.
\r
1213 * @param basePackageName
\r
1214 * string contains name of package to which augment belongs. If
\r
1215 * an augmented choice is from an other package (pcg1) than an
\r
1216 * augmenting choice (pcg2) then case's of the augmenting choice
\r
1217 * will belong to pcg2.
\r
1218 * @param refChoiceType
\r
1219 * Type which represents the choice to which case belongs. Every
\r
1220 * case has to contain its choice in extend part.
\r
1221 * @param caseNodes
\r
1222 * set of choice case nodes for which is checked if are/aren't
\r
1223 * added to choice through augmentation
\r
1224 * @return list of generated types which represents augmented cases of
\r
1225 * choice <code>refChoiceType</code>
\r
1226 * @throws IllegalArgumentException
\r
1228 * <li>if <code>basePackageName</code> equals null</li>
\r
1229 * <li>if <code>refChoiceType</code> equals null</li>
\r
1230 * <li>if <code>caseNodes</code> equals null</li>
\r
1233 private def void generateTypesFromAugmentedChoiceCases(Module module, String basePackageName, Type targetType,
1234 ChoiceNode targetNode, Set<DataSchemaNode> augmentedNodes) {
1235 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1236 checkArgument(targetType !== null, "Referenced Choice Type cannot be NULL.");
1237 checkArgument(augmentedNodes !== null, "Set of Choice Case Nodes cannot be NULL.");
1239 for (caseNode : augmentedNodes) {
1240 if (caseNode !== null) {
1241 val packageName = packageNameForGeneratedType(basePackageName, caseNode.path);
1242 val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
1243 caseTypeBuilder.addImplementsType(targetType);
1245 val SchemaNode parent = targetNode.parent as SchemaNode;
1246 var GeneratedTypeBuilder childOfType = null;
1247 if (parent instanceof Module) {
1248 childOfType = genCtx.get(parent as Module).moduleNode
1249 } else if (parent instanceof ChoiceCaseNode) {
1250 childOfType = findCaseByPath(parent.path)
1251 } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) {
1252 childOfType = findChildNodeByPath(parent.path)
1253 } else if (parent instanceof GroupingDefinition) {
1254 childOfType = findGroupingByPath(parent.path);
1257 if (childOfType == null) {
1258 throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode);
1261 if (caseNode instanceof DataNodeContainer) {
1262 val DataNodeContainer dataNodeCase = caseNode as DataNodeContainer;
1263 val Set<DataSchemaNode> childNodes = dataNodeCase.childNodes;
1264 if (childNodes !== null) {
1265 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
1268 val ChoiceCaseNode node = targetNode.getCaseNodeByName(caseNode.getQName().getLocalName());
1269 val Set<DataSchemaNode> childNodes = node.childNodes;
1270 if (childNodes !== null) {
1271 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
1275 genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder)
1282 * Converts <code>leaf</code> to the getter method which is added to
\r
1283 * <code>typeBuilder</code>.
\r
1285 * @param typeBuilder
\r
1286 * generated type builder to which is added getter method as
\r
1287 * <code>leaf</code> mapping
\r
1289 * leaf schema node which is mapped as getter method which is
\r
1290 * added to <code>typeBuilder</code>
\r
1291 * @return boolean value
\r
1293 * <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
\r
1295 * <li>true - in other cases</li>
\r
1298 private def boolean resolveLeafSchemaNodeAsMethod(GeneratedTypeBuilder typeBuilder, LeafSchemaNode leaf) {
1299 if ((leaf !== null) && (typeBuilder !== null)) {
1300 val leafName = leaf.QName.localName;
1301 var String leafDesc = leaf.description;
1302 if (leafDesc === null) {
1306 val parentModule = findParentModule(schemaContext, leaf);
1307 if (leafName !== null && !leaf.isAddedByUses()) {
1308 val TypeDefinition<?> typeDef = leaf.type;
1310 var Type returnType = null;
1311 if (typeDef instanceof EnumTypeDefinition) {
1312 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
1313 val enumTypeDef = typeDef as EnumTypeDefinition;
1314 val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leafName, typeBuilder);
1316 if (enumBuilder !== null) {
1317 returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name);
1319 (typeProvider as TypeProviderImpl).putReferencedType(leaf.path, returnType);
1320 } else if (typeDef instanceof UnionType) {
1321 val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
1322 if (genTOBuilder !== null) {
1323 returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
1325 } else if (typeDef instanceof BitsTypeDefinition) {
1326 val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
1327 if (genTOBuilder !== null) {
1328 returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
1331 val Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
\r
1332 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
1334 if (returnType !== null) {
1335 val MethodSignatureBuilder getter = constructGetter(typeBuilder, leafName, leafDesc, returnType);
1336 processContextRefExtension(leaf, getter, parentModule);
1344 private def void processContextRefExtension(LeafSchemaNode leaf, MethodSignatureBuilder getter, Module module) {
1345 for (node : leaf.unknownSchemaNodes) {
1346 val nodeType = node.nodeType;
1347 if ("context-reference".equals(nodeType.localName)) {
1348 val nodeParam = node.nodeParameter;
1349 var IdentitySchemaNode identity = null;
1350 var String basePackageName = null;
1351 val String[] splittedElement = nodeParam.split(":");
1352 if (splittedElement.length == 1) {
1353 identity = findIdentityByName(module.identities, splittedElement.get(0));
1354 basePackageName = moduleNamespaceToPackageName(module);
1355 } else if (splittedElement.length == 2) {
1356 var prefix = splittedElement.get(0);
1357 val Module dependentModule = findModuleFromImports(module.imports, prefix)
1358 if (dependentModule == null) {
1359 throw new IllegalArgumentException(
1360 "Failed to process context-reference: unknown prefix " + prefix);
1362 identity = findIdentityByName(dependentModule.identities, splittedElement.get(1));
1363 basePackageName = moduleNamespaceToPackageName(dependentModule);
1365 throw new IllegalArgumentException(
1366 "Failed to process context-reference: unknown identity " + nodeParam);
1368 if (identity == null) {
1369 throw new IllegalArgumentException(
1370 "Failed to process context-reference: unknown identity " + nodeParam);
1373 val Class<RoutingContext> clazz = typeof(RoutingContext);
1374 val AnnotationTypeBuilder rc = getter.addAnnotation(clazz.package.name, clazz.simpleName);
1375 val packageName = packageNameForGeneratedType(basePackageName, identity.path);
1376 val genTypeName = parseToClassName(identity.QName.localName);
1377 rc.addParameter("value", packageName + "." + genTypeName + ".class");
1382 private def IdentitySchemaNode findIdentityByName(Set<IdentitySchemaNode> identities, String name) {
1383 for (id : identities) {
1384 if (id.QName.localName.equals(name)) {
1391 private def Module findModuleFromImports(Set<ModuleImport> imports, String prefix) {
1392 for (imp : imports) {
1393 if (imp.prefix.equals(prefix)) {
1394 return schemaContext.findModuleByName(imp.moduleName, imp.revision);
1401 * Converts <code>leaf</code> schema node to property of generated TO
\r
1404 * @param toBuilder
\r
1405 * generated TO builder to which is <code>leaf</code> added as
\r
1408 * leaf schema node which is added to <code>toBuilder</code> as
\r
1410 * @param isReadOnly
\r
1411 * boolean value which says if leaf property is|isn't read only
\r
1412 * @return boolean value
\r
1414 * <li>false - if <code>leaf</code>, <code>toBuilder</code> or leaf
\r
1415 * name equals null or if leaf is added by <i>uses</i>.</li>
\r
1416 * <li>true - other cases</li>
\r
1419 private def boolean resolveLeafSchemaNodeAsProperty(GeneratedTOBuilder toBuilder, LeafSchemaNode leaf,
1420 boolean isReadOnly) {
1421 if ((leaf !== null) && (toBuilder !== null)) {
1422 val leafName = leaf.QName.localName;
1423 var String leafDesc = leaf.description;
1424 if (leafDesc === null) {
1428 if (leafName !== null) {
1429 val TypeDefinition<?> typeDef = leaf.type;
1431 // TODO: properly resolve enum types
\r
1432 val returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
1434 if (returnType !== null) {
1435 val propBuilder = toBuilder.addProperty(parseToClassName(leafName));
1437 propBuilder.setReadOnly(isReadOnly);
1438 propBuilder.setReturnType(returnType);
1439 propBuilder.setComment(leafDesc);
1441 toBuilder.addEqualsIdentity(propBuilder);
1442 toBuilder.addHashIdentity(propBuilder);
1443 toBuilder.addToStringProperty(propBuilder);
1453 * Converts <code>node</code> leaf list schema node to getter method of
\r
1454 * <code>typeBuilder</code>.
\r
1456 * @param typeBuilder
\r
1457 * generated type builder to which is <code>node</code> added as
\r
1460 * leaf list schema node which is added to
\r
1461 * <code>typeBuilder</code> as getter method
\r
1462 * @return boolean value
\r
1464 * <li>true - if <code>node</code>, <code>typeBuilder</code>,
\r
1465 * nodeName equal null or <code>node</code> is added by <i>uses</i></li>
\r
1466 * <li>false - other cases</li>
\r
1469 private def boolean resolveLeafListSchemaNode(GeneratedTypeBuilder typeBuilder, LeafListSchemaNode node) {
1470 if ((node !== null) && (typeBuilder !== null)) {
1471 val nodeName = node.QName.localName;
1472 var String nodeDesc = node.description;
1473 if (nodeDesc === null) {
1476 if (nodeName !== null && !node.isAddedByUses()) {
1477 val TypeDefinition<?> type = node.type;
1478 val listType = Types.listTypeFor(typeProvider.javaTypeForSchemaDefinitionType(type, node));
1479 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
1486 private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode) {
1487 return addDefaultInterfaceDefinition(packageName, schemaNode, null);
1491 * Instantiates generated type builder with <code>packageName</code> and
\r
1492 * <code>schemaNode</code>.
\r
1494 * The new builder always implements
\r
1495 * {@link org.opendaylight.yangtools.yang.binding.DataObject DataObject}.<br />
\r
1496 * If <code>schemaNode</code> is instance of GroupingDefinition it also
\r
1497 * implements {@link org.opendaylight.yangtools.yang.binding.Augmentable
\r
1498 * Augmentable}.<br />
\r
1499 * If <code>schemaNode</code> is instance of
\r
1500 * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
\r
1501 * DataNodeContainer} it can also implement nodes which are specified in
\r
1504 * @param packageName
\r
1505 * string with the name of the package to which
\r
1506 * <code>schemaNode</code> belongs.
\r
1507 * @param schemaNode
\r
1508 * schema node for which is created generated type builder
\r
1509 * @param parent parent type (can be null)
\r
1510 * @return generated type builder <code>schemaNode</code>
\r
1512 private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode,
1514 val it = addRawInterfaceDefinition(packageName, schemaNode, "");
\r
1515 val qname = schemaNode.QName;
1516 //addConstant(QName.typeForClass,"QNAME",'''
\r
1517 // org.opendaylight.yangtools.yang.common.QName.create("«qname.namespace»","«qname.formattedRevision»","«qname.localName»");
\r
1519 if (parent === null) {
1520 addImplementsType(DATA_OBJECT);
1522 addImplementsType(BindingTypes.childOf(parent));
1524 if (!(schemaNode instanceof GroupingDefinition)) {
1525 addImplementsType(augmentable(it));
1528 if (schemaNode instanceof DataNodeContainer) {
1529 addImplementedInterfaceFromUses(schemaNode as DataNodeContainer, it);
1536 * Wraps the calling of the same overloaded method.
\r
1538 * @param packageName
\r
1539 * string with the package name to which returning generated type
\r
1541 * @param schemaNode
\r
1542 * schema node which provide data about the schema node name
\r
1543 * @return generated type builder for <code>schemaNode</code>
\r
1545 private def GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode) {
1546 return addRawInterfaceDefinition(packageName, schemaNode, "");
1550 * Returns reference to generated type builder for specified
\r
1551 * <code>schemaNode</code> with <code>packageName</code>.
\r
1553 * Firstly the generated type builder is searched in
\r
1554 * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
\r
1555 * found it is created and added to <code>genTypeBuilders</code>.
\r
1557 * @param packageName
\r
1558 * string with the package name to which returning generated type
\r
1560 * @param schemaNode
\r
1561 * schema node which provide data about the schema node name
\r
1562 * @param prefix return type name prefix
\r
1563 * @return generated type builder for <code>schemaNode</code>
\r
1564 * @throws IllegalArgumentException
\r
1566 * <li>if <code>schemaNode</code> equals null</li>
\r
1567 * <li>if <code>packageName</code> equals null</li>
\r
1568 * <li>if Q name of schema node is null</li>
\r
1569 * <li>if schema node name is nul</li>
\r
1573 private def GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode,
1575 checkArgument(schemaNode !== null, "Data Schema Node cannot be NULL.");
1576 checkArgument(packageName !== null, "Package Name for Generated Type cannot be NULL.");
1577 checkArgument(schemaNode.QName !== null, "QName for Data Schema Node cannot be NULL.");
1578 val schemaNodeName = schemaNode.QName.localName;
1579 checkArgument(schemaNodeName !== null, "Local Name of QName for Data Schema Node cannot be NULL.");
1581 var String genTypeName;
1582 if (prefix === null) {
1583 genTypeName = parseToClassName(schemaNodeName);
1585 genTypeName = prefix + parseToClassName(schemaNodeName);
1588 //FIXME: Validation of name conflict
\r
1589 val newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
1590 if (!genTypeBuilders.containsKey(packageName)) {
1591 val Map<String, GeneratedTypeBuilder> builders = new HashMap();
1592 builders.put(genTypeName, newType);
1593 genTypeBuilders.put(packageName, builders);
1595 val Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
1596 if (!builders.containsKey(genTypeName)) {
1597 builders.put(genTypeName, newType);
1604 * Creates the name of the getter method from <code>methodName</code>.
\r
1606 * @param methodName
\r
1607 * string with the name of the getter method
\r
1608 * @param returnType return type
\r
1609 * @return string with the name of the getter method for
\r
1610 * <code>methodName</code> in JAVA method format
\r
1612 public static def String getterMethodName(String localName, Type returnType) {
1613 val method = new StringBuilder();
1614 if (BOOLEAN.equals(returnType)) {
1615 method.append("is");
1617 method.append("get");
1619 method.append(parseToClassName(localName));
1620 return method.toString();
1624 * Created a method signature builder as part of
\r
1625 * <code>interfaceBuilder</code>.
\r
1627 * The method signature builder is created for the getter method of
\r
1628 * <code>schemaNodeName</code>. Also <code>comment</code> and
\r
1629 * <code>returnType</code> information are added to the builder.
\r
1631 * @param interfaceBuilder
\r
1632 * generated type builder for which the getter method should be
\r
1634 * @param schemaNodeName
\r
1635 * string with schema node name. The name will be the part of the
\r
1636 * getter method name.
\r
1638 * string with comment for the getter method
\r
1639 * @param returnType
\r
1640 * type which represents the return type of the getter method
\r
1641 * @return method signature builder which represents the getter method of
\r
1642 * <code>interfaceBuilder</code>
\r
1644 private def MethodSignatureBuilder constructGetter(GeneratedTypeBuilder interfaceBuilder, String schemaNodeName,
1645 String comment, Type returnType) {
1646 val getMethod = interfaceBuilder.addMethod(getterMethodName(schemaNodeName, returnType));
1647 getMethod.setComment(comment);
1648 getMethod.setReturnType(returnType);
1653 * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
\r
1654 * or to <code>genTOBuilder</code> as property.
\r
1656 * @param basePackageName
\r
1657 * string contains the module package name
\r
1658 * @param schemaNode
\r
1659 * data schema node which should be added as getter method to
\r
1660 * <code>typeBuilder</code> or as a property to
\r
1661 * <code>genTOBuilder</code> if is part of the list key
\r
1662 * @param typeBuilder
\r
1663 * generated type builder for the list schema node
\r
1664 * @param genTOBuilder
\r
1665 * generated TO builder for the list keys
\r
1667 * list of string which contains names of the list keys
\r
1668 * @param module current module
\r
1669 * @throws IllegalArgumentException
\r
1671 * <li>if <code>schemaNode</code> equals null</li>
\r
1672 * <li>if <code>typeBuilder</code> equals null</li>
\r
1675 private def void addSchemaNodeToListBuilders(String basePackageName, DataSchemaNode schemaNode,
1676 GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder, List<String> listKeys, Module module) {
1677 checkArgument(schemaNode !== null, "Data Schema Node cannot be NULL.");
1678 checkArgument(typeBuilder !== null, "Generated Type Builder cannot be NULL.");
1680 if (schemaNode instanceof LeafSchemaNode) {
1681 val leaf = schemaNode as LeafSchemaNode;
1682 val leafName = leaf.QName.localName;
1683 if (!listKeys.contains(leafName)) {
1684 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
1686 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
1688 } else if (!schemaNode.addedByUses) {
1689 if (schemaNode instanceof LeafListSchemaNode) {
1690 resolveLeafListSchemaNode(typeBuilder, schemaNode as LeafListSchemaNode);
1691 } else if (schemaNode instanceof ContainerSchemaNode) {
1692 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, schemaNode as ContainerSchemaNode);
1693 } else if (schemaNode instanceof ChoiceNode) {
1694 choiceToGeneratedType(module, basePackageName, typeBuilder, schemaNode as ChoiceNode);
1695 } else if (schemaNode instanceof ListSchemaNode) {
1696 listToGenType(module, basePackageName, typeBuilder, typeBuilder, schemaNode as ListSchemaNode);
1701 private def typeBuildersToGenTypes(Module module, GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder) {
1702 checkArgument(typeBuilder !== null, "Generated Type Builder cannot be NULL.");
1704 if (genTOBuilder !== null) {
1705 val genTO = genTOBuilder.toInstance();
1706 constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO);
1707 genCtx.get(module).addGeneratedTOBuilder(genTOBuilder)
1712 * Selects the names of the list keys from <code>list</code> and returns
\r
1713 * them as the list of the strings
\r
1716 * of string with names of the list keys
\r
1717 * @return list of string which represents names of the list keys. If the
\r
1718 * <code>list</code> contains no keys then the empty list is
\r
1721 private def listKeys(ListSchemaNode list) {
1722 val List<String> listKeys = new ArrayList();
1724 if (list.keyDefinition !== null) {
1725 val keyDefinitions = list.keyDefinition;
1726 for (keyDefinition : keyDefinitions) {
1727 listKeys.add(keyDefinition.localName);
1734 * Generates for the <code>list</code> which contains any list keys special
\r
1735 * generated TO builder.
\r
1737 * @param packageName
\r
1738 * string with package name to which the list belongs
\r
1740 * list schema node which is source of data about the list name
\r
1741 * @return generated TO builder which represents the keys of the
\r
1742 * <code>list</code> or null if <code>list</code> is null or list of
\r
1743 * key definitions is null or empty.
\r
1745 private def GeneratedTOBuilder resolveListKeyTOBuilder(String packageName, ListSchemaNode list) {
1746 var GeneratedTOBuilder genTOBuilder = null;
1747 if ((list.keyDefinition !== null) && (!list.keyDefinition.isEmpty())) {
1748 if (list !== null) {
1749 val listName = list.QName.localName + "Key";
1750 val String genTOName = parseToClassName(listName);
1751 genTOBuilder = new GeneratedTOBuilderImpl(packageName, genTOName);
1754 return genTOBuilder;
1758 * Builds generated TO builders for <code>typeDef</code> of type
\r
1759 * {@link org.opendaylight.yangtools.yang.model.util.UnionType UnionType} or
\r
1760 * {@link org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
\r
1761 * BitsTypeDefinition} which are also added to <code>typeBuilder</code> as
\r
1762 * enclosing transfer object.
\r
1764 * If more then one generated TO builder is created for enclosing then all
\r
1765 * of the generated TO builders are added to <code>typeBuilder</code> as
\r
1766 * enclosing transfer objects.
\r
1769 * type definition which can be of type <code>UnionType</code> or
\r
1770 * <code>BitsTypeDefinition</code>
\r
1771 * @param typeBuilder
\r
1772 * generated type builder to which is added generated TO created
\r
1773 * from <code>typeDef</code>
\r
1775 * string with name for generated TO builder
\r
1777 * @param parentModule
\r
1778 * @return generated TO builder for <code>typeDef</code>
\r
1780 private def GeneratedTOBuilder addTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
1781 String leafName, LeafSchemaNode leaf, Module parentModule) {
1782 val classNameFromLeaf = parseToClassName(leafName);
1783 val List<GeneratedTOBuilder> genTOBuilders = new ArrayList();
1784 val packageName = typeBuilder.fullyQualifiedName;
1785 if (typeDef instanceof UnionTypeDefinition) {
1786 genTOBuilders.addAll(
1787 (typeProvider as TypeProviderImpl).
1788 provideGeneratedTOBuildersForUnionTypeDef(packageName, (typeDef as UnionTypeDefinition),
1789 classNameFromLeaf, leaf));
1790 } else if (typeDef instanceof BitsTypeDefinition) {
1792 ((typeProvider as TypeProviderImpl) ).
1793 provideGeneratedTOBuilderForBitsTypeDefinition(packageName, typeDef, classNameFromLeaf));
1795 if (genTOBuilders !== null && !genTOBuilders.isEmpty()) {
1796 for (genTOBuilder : genTOBuilders) {
1797 typeBuilder.addEnclosingTransferObject(genTOBuilder);
1799 return genTOBuilders.get(0);
1806 * Adds the implemented types to type builder.
\r
1808 * The method passes through the list of <i>uses</i> in
\r
1809 * {@code dataNodeContainer}. For every <i>use</i> is obtained coresponding
\r
1810 * generated type from {@link BindingGeneratorImpl#allGroupings
\r
1811 * allGroupings} which is added as <i>implements type</i> to
\r
1812 * <code>builder</code>
\r
1814 * @param dataNodeContainer
\r
1815 * element which contains the list of used YANG groupings
\r
1817 * builder to which are added implemented types according to
\r
1818 * <code>dataNodeContainer</code>
\r
1819 * @return generated type builder with all implemented types
\r
1821 private def addImplementedInterfaceFromUses(DataNodeContainer dataNodeContainer, GeneratedTypeBuilder builder) {
1822 for (usesNode : dataNodeContainer.uses) {
1823 if (usesNode.groupingPath !== null) {
1824 val genType = findGroupingByPath(usesNode.groupingPath).toInstance
1825 if (genType === null) {
1826 throw new IllegalStateException(
1827 "Grouping " + usesNode.groupingPath + "is not resolved for " + builder.name);
1829 builder.addImplementsType(genType);
1835 private def GeneratedTypeBuilder findChildNodeByPath(SchemaPath path) {
1836 for (ctx : genCtx.values) {
1837 var result = ctx.getChildNode(path)
1838 if (result !== null) {
1845 private def GeneratedTypeBuilder findGroupingByPath(SchemaPath path) {
1846 for (ctx : genCtx.values) {
1847 var result = ctx.getGrouping(path)
1848 if (result !== null) {
1855 private def GeneratedTypeBuilder findCaseByPath(SchemaPath path) {
1856 for (ctx : genCtx.values) {
1857 var result = ctx.getCase(path)
1858 if (result !== null) {
1866 public def getModuleContexts() {
\r