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
77 public class BindingGeneratorImpl implements BindingGenerator {
79 private final Map<Module, ModuleContext> genCtx = new HashMap()
82 * Outter key represents the package name. Outter value represents map of
\r
83 * all builders in the same package. Inner key represents the schema node
\r
84 * name (in JAVA class/interface name format). Inner value represents
\r
85 * instance of builder for schema node specified in key part.
\r
87 private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
90 * Provide methods for converting YANG types to JAVA types.
\r
92 private var TypeProvider typeProvider;
95 * Holds reference to schema context to resolve data of augmented elemnt
\r
96 * when creating augmentation builder
\r
98 private var SchemaContext schemaContext;
101 * Constant with the concrete name of namespace.
\r
103 private val static String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
106 * Constant with the concrete name of identifier.
\r
108 private val static String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
111 * Resolves generated types from <code>context</code> schema nodes of all
\r
114 * Generated types are created for modules, groupings, types, containers,
\r
115 * lists, choices, augments, rpcs, notification, identities.
\r
118 * schema context which contains data about all schema nodes
\r
120 * @return list of types (usually <code>GeneratedType</code>
\r
121 * <code>GeneratedTransferObject</code>which are generated from
\r
122 * <code>context</code> data.
\r
123 * @throws IllegalArgumentException
\r
124 * if param <code>context</code> is null
\r
125 * @throws IllegalStateException
\r
126 * if <code>context</code> contain no modules
\r
128 override generateTypes(SchemaContext context) {
129 checkArgument(context !== null, "Schema Context reference cannot be NULL.");
130 checkState(context.modules !== null, "Schema Context does not contain defined modules.");
131 schemaContext = context;
132 typeProvider = new TypeProviderImpl(context);
133 val Set<Module> modules = context.modules;
134 return generateTypes(context, modules);
138 * Resolves generated types from <code>context</code> schema nodes only for
\r
139 * modules specified in <code>modules</code>
\r
141 * Generated types are created for modules, groupings, types, containers,
\r
142 * lists, choices, augments, rpcs, notification, identities.
\r
145 * schema context which contains data about all schema nodes
\r
148 * set of modules for which schema nodes should be generated
\r
150 * @return list of types (usually <code>GeneratedType</code> or
\r
151 * <code>GeneratedTransferObject</code>) which:
\r
153 * <li>are generated from <code>context</code> schema nodes and</li>
\r
154 * <li>are also part of some of the module in <code>modules</code>
\r
157 * @throws IllegalArgumentException
\r
159 * <li>if param <code>context</code> is null or</li>
\r
160 * <li>if param <code>modules</code> is null</li>
\r
162 * @throws IllegalStateException
\r
163 * if <code>context</code> contain no modules
\r
165 override generateTypes(SchemaContext context, Set<Module> modules) {
166 checkArgument(context !== null, "Schema Context reference cannot be NULL.");
167 checkState(context.modules !== null, "Schema Context does not contain defined modules.");
168 checkArgument(modules !== null, "Set of Modules cannot be NULL.");
170 schemaContext = context;
171 typeProvider = new TypeProviderImpl(context);
172 val contextModules = ModuleDependencySort.sort(context.modules);
173 genTypeBuilders = new HashMap();
175 for (contextModule : contextModules) {
176 moduleToGenTypes(contextModule, context);
178 for (contextModule : contextModules) {
179 allAugmentsToGenTypes(contextModule);
182 val List<Type> filteredGenTypes = new ArrayList();
183 for (Module m : modules) {
184 filteredGenTypes.addAll(genCtx.get(m).generatedTypes);
189 return filteredGenTypes;
192 private def void moduleToGenTypes(Module m, SchemaContext context) {
193 genCtx.put(m, new ModuleContext)
194 allTypeDefinitionsToGenTypes(m)
195 groupingsToGenTypes(m, m.groupings)
196 rpcMethodsToGenType(m)
197 allIdentitiesToGenTypes(m, context)
198 notificationsToGenType(m)
200 if (!m.childNodes.isEmpty()) {
201 val moduleType = moduleToDataType(m)
202 genCtx.get(m).addModuleNode(moduleType)
203 val basePackageName = moduleNamespaceToPackageName(m);
204 resolveDataSchemaNodes(m, basePackageName, moduleType, moduleType, m.childNodes)
209 * Converts all extended type definitions of module to the list of
\r
210 * <code>Type</code> objects.
\r
213 * module from which is obtained set of type definitions
\r
214 * @throws IllegalArgumentException
\r
216 * <li>if module equals null</li>
\r
217 * <li>if name of module equals null</li>
\r
218 * <li>if type definitions of module equal null</li>
\r
222 private def void allTypeDefinitionsToGenTypes(Module module) {
223 checkArgument(module !== null, "Module reference cannot be NULL.");
224 checkArgument(module.name !== null, "Module name cannot be NULL.");
225 val it = new DataNodeIterator(module);
226 val List<TypeDefinition<?>> typeDefinitions = it.allTypedefs;
227 checkState(typeDefinitions !== null, '''Type Definitions for module «module.name» cannot be NULL.''');
229 for (TypeDefinition<?> typedef : typeDefinitions) {
230 if (typedef !== null) {
231 val type = (typeProvider as TypeProviderImpl).generatedTypeForExtendedDefinitionType(typedef, typedef);
233 genCtx.get(module).addTypedefType(typedef.path, type)
239 private def void containerToGenType(Module module, String basePackageName, GeneratedTypeBuilder parent,
240 GeneratedTypeBuilder childOf, ContainerSchemaNode node) {
241 if (node.augmenting || node.addedByUses) {
244 val packageName = packageNameForGeneratedType(basePackageName, node.path)
245 val genType = addDefaultInterfaceDefinition(packageName, node, childOf)
246 constructGetter(parent, node.QName.localName, node.description, genType)
247 genCtx.get(module).addChildNodeType(node.path, genType)
248 resolveDataSchemaNodes(module, basePackageName, genType, genType, node.childNodes)
249 groupingsToGenTypes(module, node.groupings)
250 processUsesAugments(node, module)
253 private def void listToGenType(Module module, String basePackageName, GeneratedTypeBuilder parent,
254 GeneratedTypeBuilder childOf, ListSchemaNode node) {
255 if (node.augmenting || node.addedByUses) {
258 val packageName = packageNameForGeneratedType(basePackageName, (node).path)
259 val genType = addDefaultInterfaceDefinition(packageName, node, childOf)
260 constructGetter(parent, node.QName.localName, node.description, Types.listTypeFor(genType))
261 genCtx.get(module).addChildNodeType(node.path, genType)
262 groupingsToGenTypes(module, node.groupings)
263 processUsesAugments(node, module)
265 val List<String> listKeys = listKeys(node);
266 val genTOBuilder = resolveListKeyTOBuilder(packageName, node);
268 if (genTOBuilder !== null) {
269 val identifierMarker = IDENTIFIER.parameterizedTypeFor(genType);
270 val identifiableMarker = IDENTIFIABLE.parameterizedTypeFor(genTOBuilder);
271 genTOBuilder.addImplementsType(identifierMarker);
272 genType.addImplementsType(identifiableMarker);
275 for (schemaNode : node.childNodes) {
276 if (!schemaNode.augmenting) {
277 addSchemaNodeToListBuilders(basePackageName, schemaNode, genType, genTOBuilder, listKeys, module);
281 typeBuildersToGenTypes(module, genType, genTOBuilder);
284 private def void processUsesAugments(DataNodeContainer node, Module module) {
285 val basePackageName = moduleNamespaceToPackageName(module);
286 for (usesNode : node.uses) {
287 for (augment : usesNode.augmentations) {
288 augmentationToGenTypes(basePackageName, augment, module, usesNode);
289 processUsesAugments(augment, module);
295 * Converts all <b>augmentation</b> of the module to the list
\r
296 * <code>Type</code> objects.
\r
299 * module from which is obtained list of all augmentation objects
\r
300 * to iterate over them
\r
301 * @throws IllegalArgumentException
\r
303 * <li>if the module equals null</li>
\r
304 * <li>if the name of module equals null</li>
\r
305 * <li>if the set of child nodes equals null</li>
\r
309 private def void allAugmentsToGenTypes(Module module) {
310 checkArgument(module !== null, "Module reference cannot be NULL.");
311 checkArgument(module.name !== null, "Module name cannot be NULL.");
312 if (module.childNodes === null) {
313 throw new IllegalArgumentException(
314 "Reference to Set of Augmentation Definitions in module " + module.name + " cannot be NULL.");
317 val basePackageName = moduleNamespaceToPackageName(module);
318 val List<AugmentationSchema> augmentations = resolveAugmentations(module);
319 for (augment : augmentations) {
320 augmentationToGenTypes(basePackageName, augment, module, null);
325 * Returns list of <code>AugmentationSchema</code> objects. The objects are
\r
326 * sorted according to the length of their target path from the shortest to
\r
330 * module from which is obtained list of all augmentation objects
\r
331 * @return list of sorted <code>AugmentationSchema</code> objects obtained
\r
332 * from <code>module</code>
\r
333 * @throws IllegalArgumentException
\r
335 * <li>if the module equals null</li>
\r
336 * <li>if the set of augmentation equals null</li>
\r
340 private def List<AugmentationSchema> resolveAugmentations(Module module) {
341 checkArgument(module !== null, "Module reference cannot be NULL.");
342 checkState(module.augmentations !== null, "Augmentations Set cannot be NULL.");
344 val Set<AugmentationSchema> augmentations = module.augmentations;
345 val List<AugmentationSchema> sortedAugmentations = new ArrayList(augmentations);
346 Collections.sort(sortedAugmentations,
347 [ augSchema1, augSchema2 |
348 if (augSchema1.targetPath.path.size() > augSchema2.targetPath.path.size()) {
350 } else if (augSchema1.targetPath.path.size() < augSchema2.targetPath.path.size()) {
355 return sortedAugmentations;
359 * Converts whole <b>module</b> to <code>GeneratedType</code> object.
\r
360 * Firstly is created the module builder object from which is vally
\r
361 * obtained reference to <code>GeneratedType</code> object.
\r
364 * module from which are obtained the module name, child nodes,
\r
365 * uses and is derived package name
\r
366 * @return <code>GeneratedType</code> which is internal representation of
\r
368 * @throws IllegalArgumentException
\r
369 * if the module equals null
\r
372 private def GeneratedTypeBuilder moduleToDataType(Module module) {
373 checkArgument(module !== null, "Module reference cannot be NULL.");
375 val moduleDataTypeBuilder = moduleTypeBuilder(module, "Data");
376 addImplementedInterfaceFromUses(module, moduleDataTypeBuilder);
377 moduleDataTypeBuilder.addImplementsType(DATA_ROOT);
378 return moduleDataTypeBuilder;
382 * Converts all <b>rpcs</b> inputs and outputs substatements of the module
\r
383 * to the list of <code>Type</code> objects. In addition are to containers
\r
384 * and lists which belong to input or output also part of returning list.
\r
387 * module from which is obtained set of all rpc objects to
\r
388 * iterate over them
\r
389 * @throws IllegalArgumentException
\r
391 * <li>if the module equals null</li>
\r
392 * <li>if the name of module equals null</li>
\r
393 * <li>if the set of child nodes equals null</li>
\r
397 private def void rpcMethodsToGenType(Module module) {
398 checkArgument(module !== null, "Module reference cannot be NULL.");
399 checkArgument(module.name !== null, "Module name cannot be NULL.");
400 checkArgument(module.childNodes !== null,
401 "Reference to Set of RPC Method Definitions in module " + module.name + " cannot be NULL.");
403 val basePackageName = moduleNamespaceToPackageName(module);
404 val Set<RpcDefinition> rpcDefinitions = module.rpcs;
405 if (rpcDefinitions.isEmpty()) {
409 val interfaceBuilder = moduleTypeBuilder(module, "Service");
410 interfaceBuilder.addImplementsType(Types.typeForClass(RpcService));
411 for (rpc : rpcDefinitions) {
413 val rpcName = parseToClassName(rpc.QName.localName);
414 val rpcMethodName = parseToValidParamName(rpcName);
415 val method = interfaceBuilder.addMethod(rpcMethodName);
416 val input = rpc.input;
417 val output = rpc.output;
419 if (input !== null) {
420 val inType = addRawInterfaceDefinition(basePackageName, input, rpcName);
421 addImplementedInterfaceFromUses(input, inType);
422 inType.addImplementsType(DATA_OBJECT);
423 inType.addImplementsType(augmentable(inType));
424 resolveDataSchemaNodes(module, basePackageName, inType, inType, input.childNodes);
425 genCtx.get(module).addChildNodeType(input.path, inType)
426 val inTypeInstance = inType.toInstance();
427 method.addParameter(inTypeInstance, "input");
430 var Type outTypeInstance = VOID;
431 if (output !== null) {
432 val outType = addRawInterfaceDefinition(basePackageName, output, rpcName);
433 addImplementedInterfaceFromUses(output, outType);
434 outType.addImplementsType(DATA_OBJECT);
435 outType.addImplementsType(augmentable(outType));
436 resolveDataSchemaNodes(module, basePackageName, outType, outType, output.childNodes);
437 genCtx.get(module).addChildNodeType(output.path, outType)
438 outTypeInstance = outType.toInstance();
441 val rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult), outTypeInstance);
442 method.setReturnType(Types.parameterizedTypeFor(FUTURE, rpcRes));
446 genCtx.get(module).addTopLevelNodeType(interfaceBuilder)
450 * Converts all <b>notifications</b> of the module to the list of
\r
451 * <code>Type</code> objects. In addition are to this list added containers
\r
452 * and lists which are part of this notification.
\r
455 * module from which is obtained set of all notification objects
\r
456 * to iterate over them
\r
457 * @throws IllegalArgumentException
\r
459 * <li>if the module equals null</li>
\r
460 * <li>if the name of module equals null</li>
\r
461 * <li>if the set of child nodes equals null</li>
\r
465 private def void notificationsToGenType(Module module) {
466 checkArgument(module !== null, "Module reference cannot be NULL.");
467 checkArgument(module.name !== null, "Module name cannot be NULL.");
469 if (module.childNodes === null) {
470 throw new IllegalArgumentException(
471 "Reference to Set of Notification Definitions in module " + module.name + " cannot be NULL.");
473 val notifications = module.notifications;
474 if(notifications.empty) return;
476 val listenerInterface = moduleTypeBuilder(module, "Listener");
477 listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER);
478 val basePackageName = moduleNamespaceToPackageName(module);
480 for (notification : notifications) {
481 if (notification !== null) {
482 processUsesAugments(notification, module);
484 val notificationInterface = addDefaultInterfaceDefinition(basePackageName, notification,
485 BindingTypes.DATA_OBJECT);
486 notificationInterface.addImplementsType(NOTIFICATION);
487 genCtx.get(module).addChildNodeType(notification.path, notificationInterface)
489 // Notification object
\r
490 resolveDataSchemaNodes(module, basePackageName, notificationInterface, notificationInterface,
491 notification.childNodes);
493 listenerInterface.addMethod("on" + notificationInterface.name) //
\r
494 .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification").
495 setReturnType(Types.VOID);
499 genCtx.get(module).addTopLevelNodeType(listenerInterface)
503 * Converts all <b>identities</b> of the module to the list of
\r
504 * <code>Type</code> objects.
\r
507 * module from which is obtained set of all identity objects to
\r
508 * iterate over them
\r
510 * schema context only used as input parameter for method
\r
511 * {@link identityToGenType}
\r
514 private def void allIdentitiesToGenTypes(Module module, SchemaContext context) {
515 val Set<IdentitySchemaNode> schemaIdentities = module.identities;
516 val basePackageName = moduleNamespaceToPackageName(module);
518 if (schemaIdentities !== null && !schemaIdentities.isEmpty()) {
519 for (identity : schemaIdentities) {
520 identityToGenType(module, basePackageName, identity, context);
526 * Converts the <b>identity</b> object to GeneratedType. Firstly it is
\r
527 * created transport object builder. If identity contains base identity then
\r
528 * reference to base identity is added to superior identity as its extend.
\r
529 * If identity doesn't contain base identity then only reference to abstract
\r
530 * class {@link org.opendaylight.yangtools.yang.model.api.BaseIdentity
\r
531 * BaseIdentity} is added
\r
533 * @param module current module
\r
534 * @param basePackageName
\r
535 * string contains the module package name
\r
537 * IdentitySchemaNode which contains data about identity
\r
539 * SchemaContext which is used to get package and name
\r
540 * information about base of identity
\r
543 private def void identityToGenType(Module module, String basePackageName, IdentitySchemaNode identity,
544 SchemaContext context) {
545 if (identity === null) {
548 val packageName = packageNameForGeneratedType(basePackageName, identity.path);
549 val genTypeName = parseToClassName(identity.QName.localName);
550 val newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
551 val baseIdentity = identity.baseIdentity;
552 if (baseIdentity === null) {
553 newType.setExtendsType(Types.baseIdentityTO);
555 val baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
556 val returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule);
557 val returnTypeName = parseToClassName(baseIdentity.QName.localName);
558 val gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName).toInstance();
559 newType.setExtendsType(gto);
561 newType.setAbstract(true);
562 genCtx.get(module).addIdentityType(newType)
566 * Converts all <b>groupings</b> of the module to the list of
\r
567 * <code>Type</code> objects. Firstly are groupings sorted according mutual
\r
568 * dependencies. At least dependend (indepedent) groupings are in the list
\r
569 * saved at first positions. For every grouping the record is added to map
\r
570 * {@link BindingGeneratorImpl#allGroupings allGroupings}
\r
574 * @param collection of groupings from which types will be generated
\r
577 private def void groupingsToGenTypes(Module module, Collection<GroupingDefinition> groupings) {
578 val basePackageName = moduleNamespaceToPackageName(module);
579 val List<GroupingDefinition> groupingsSortedByDependencies = new GroupingDefinitionDependencySort().sort(
581 for (grouping : groupingsSortedByDependencies) {
582 groupingToGenType(basePackageName, grouping, module);
587 * Converts individual grouping to GeneratedType. Firstly generated type
\r
588 * builder is created and every child node of grouping is resolved to the
\r
591 * @param basePackageName
\r
592 * string contains the module package name
\r
594 * GroupingDefinition which contains data about grouping
\r
595 * @param module current module
\r
596 * @return GeneratedType which is generated from grouping (object of type
\r
597 * <code>GroupingDefinition</code>)
\r
599 private def void groupingToGenType(String basePackageName, GroupingDefinition grouping, Module module) {
600 val packageName = packageNameForGeneratedType(basePackageName, grouping.path);
601 val genType = addDefaultInterfaceDefinition(packageName, grouping);
602 genCtx.get(module).addGroupingType(grouping.path, genType)
603 resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.childNodes);
604 groupingsToGenTypes(module, grouping.groupings);
605 processUsesAugments(grouping, module);
609 * Tries to find EnumTypeDefinition in <code>typeDefinition</code>. If base
\r
610 * type of <code>typeDefinition</code> is of the type ExtendedType then this
\r
611 * method is recursivelly called with this base type.
\r
613 * @param typeDefinition
\r
614 * TypeDefinition in which should be EnumTypeDefinition found as
\r
616 * @return EnumTypeDefinition if it is found inside
\r
617 * <code>typeDefinition</code> or <code>null</code> in other case
\r
619 private def EnumTypeDefinition enumTypeDefFromExtendedType(TypeDefinition<?> typeDefinition) {
620 if (typeDefinition !== null) {
621 if (typeDefinition.baseType instanceof EnumTypeDefinition) {
622 return typeDefinition.baseType as EnumTypeDefinition;
623 } else if (typeDefinition.baseType instanceof ExtendedType) {
624 return enumTypeDefFromExtendedType(typeDefinition.baseType);
631 * Adds enumeration builder created from <code>enumTypeDef</code> to
\r
632 * <code>typeBuilder</code>.
\r
634 * Each <code>enumTypeDef</code> item is added to builder with its name and
\r
637 * @param enumTypeDef
\r
638 * EnumTypeDefinition contains enum data
\r
640 * string contains name which will be assigned to enumeration
\r
642 * @param typeBuilder
\r
643 * GeneratedTypeBuilder to which will be enum builder assigned
\r
644 * @return enumeration builder which contais data from
\r
645 * <code>enumTypeDef</code>
\r
647 private def EnumBuilder resolveInnerEnumFromTypeDefinition(EnumTypeDefinition enumTypeDef, String enumName,
648 GeneratedTypeBuilder typeBuilder) {
649 if ((enumTypeDef !== null) && (typeBuilder !== null) && (enumTypeDef.QName !== null) &&
650 (enumTypeDef.QName.localName !== null)) {
651 val enumerationName = parseToClassName(enumName);
652 val enumBuilder = typeBuilder.addEnumeration(enumerationName);
653 enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
660 * Generates type builder for <code>module</code>.
\r
663 * Module which is source of package name for generated type
\r
666 * string which is added to the module class name representation
\r
668 * @return instance of GeneratedTypeBuilder which represents
\r
669 * <code>module</code>.
\r
670 * @throws IllegalArgumentException
\r
671 * if <code>module</code> equals null
\r
673 private def GeneratedTypeBuilder moduleTypeBuilder(Module module, String postfix) {
674 checkArgument(module !== null, "Module reference cannot be NULL.");
675 val packageName = moduleNamespaceToPackageName(module);
676 val moduleName = parseToClassName(module.name) + postfix;
677 return new GeneratedTypeBuilderImpl(packageName, moduleName);
681 * Converts <code>augSchema</code> to list of <code>Type</code> which
\r
682 * contains generated type for augmentation. In addition there are also
\r
683 * generated types for all containers, list and choices which are child of
\r
684 * <code>augSchema</code> node or a generated types for cases are added if
\r
685 * augmented node is choice.
\r
687 * @param augmentPackageName
\r
688 * string with the name of the package to which the augmentation
\r
691 * AugmentationSchema which is contains data about agumentation
\r
692 * (target path, childs...)
\r
693 * @param module current module
\r
694 * @param parentUsesNode parent uses node of this augment (can be null if this augment is not defined under uses statement)
\r
695 * @throws IllegalArgumentException
\r
697 * <li>if <code>augmentPackageName</code> equals null</li>
\r
698 * <li>if <code>augSchema</code> equals null</li>
\r
699 * <li>if target path of <code>augSchema</code> equals null</li>
\r
702 private def void augmentationToGenTypes(String augmentPackageName, AugmentationSchema augSchema, Module module,
703 UsesNode parentUsesNode) {
704 checkArgument(augmentPackageName !== null, "Package Name cannot be NULL.");
705 checkArgument(augSchema !== null, "Augmentation Schema cannot be NULL.");
706 checkState(augSchema.targetPath !== null,
707 "Augmentation Schema does not contain Target Path (Target Path is NULL).");
709 processUsesAugments(augSchema, module);
711 // EVERY augmented interface will extends Augmentation<T> interface
\r
712 // and DataObject interface
\r
713 val targetPath = augSchema.targetPath;
714 var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
715 if (targetSchemaNode instanceof DataSchemaNode && (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
716 if (parentUsesNode == null) {
717 targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
719 targetSchemaNode = findOriginalTargetFromGrouping(targetSchemaNode.QName.localName, parentUsesNode);
721 if (targetSchemaNode == null) {
722 throw new NullPointerException(
723 "Failed to find target node from grouping for augmentation " + augSchema + " in module " +
728 if (targetSchemaNode !== null) {
729 var targetTypeBuilder = findChildNodeByPath(targetSchemaNode.path)
730 if (targetTypeBuilder === null) {
731 targetTypeBuilder = findCaseByPath(targetSchemaNode.path)
733 if (targetTypeBuilder === null) {
734 throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
736 if (!(targetSchemaNode instanceof ChoiceNode)) {
737 var packageName = augmentPackageName;
738 if (parentUsesNode != null) {
739 packageName = packageNameForGeneratedType(augmentPackageName, augSchema.targetPath);
741 val augTypeBuilder = addRawAugmentGenTypeDefinition(module, packageName, augmentPackageName,
742 targetTypeBuilder.toInstance, augSchema);
743 genCtx.get(module).addAugmentType(augTypeBuilder)
745 generateTypesFromAugmentedChoiceCases(module, augmentPackageName, targetTypeBuilder.toInstance,
746 targetSchemaNode as ChoiceNode, augSchema.childNodes);
752 * Utility method which search for original node defined in grouping.
\r
754 private def DataSchemaNode findOriginal(DataSchemaNode node) {
755 var DataSchemaNode result = findCorrectTargetFromGrouping(node);
756 if (result == null) {
757 result = findCorrectTargetFromAugment(node);
758 if (result != null) {
759 if (result.addedByUses) {
760 result = findOriginal(result);
767 private def DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node) {
768 if (!node.augmenting) {
772 var String currentName = node.QName.localName;
773 var tmpPath = new ArrayList<String>();
774 var YangNode parent = node;
775 var AugmentationSchema augment = null;
777 parent = (parent as DataSchemaNode).parent;
778 if (parent instanceof AugmentationTarget) {
779 tmpPath.add(currentName);
780 augment = findNodeInAugment((parent as AugmentationTarget).availableAugmentations, currentName);
781 if (augment == null) {
782 currentName = (parent as DataSchemaNode).QName.localName;
785 } while ((parent as DataSchemaNode).augmenting && augment == null);
787 if (augment == null) {
790 Collections.reverse(tmpPath);
791 var Object actualParent = augment;
792 var DataSchemaNode result = null;
793 for (name : tmpPath) {
794 if (actualParent instanceof DataNodeContainer) {
795 result = (actualParent as DataNodeContainer).getDataChildByName(name);
796 actualParent = (actualParent as DataNodeContainer).getDataChildByName(name);
798 if (actualParent instanceof ChoiceNode) {
799 result = (actualParent as ChoiceNode).getCaseNodeByName(name);
800 actualParent = (actualParent as ChoiceNode).getCaseNodeByName(name);
805 if (result.addedByUses) {
806 result = findCorrectTargetFromGrouping(result);
813 private def AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, String name) {
814 for (augment : augments) {
815 if (augment.getDataChildByName(name) != null) {
822 private def DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node) {
823 if (node.path.path.size == 1) {
825 // uses is under module statement
\r
826 val Module m = findParentModule(schemaContext, node);
827 var DataSchemaNode result = null;
829 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
830 if (!(targetGrouping instanceof GroupingDefinition)) {
831 throw new IllegalArgumentException("Failed to generate code for augment in " + u);
833 var gr = targetGrouping as GroupingDefinition;
834 result = gr.getDataChildByName(node.QName.localName);
836 if (result == null) {
837 throw new IllegalArgumentException("Failed to generate code for augment");
841 var DataSchemaNode result = null;
842 var String currentName = node.QName.localName;
843 var tmpPath = new ArrayList<String>();
844 var YangNode parent = node.parent;
846 tmpPath.add(currentName);
847 val dataNodeParent = parent as DataNodeContainer;
848 for (u : dataNodeParent.uses) {
849 if (result == null) {
\r
850 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
851 if (!(targetGrouping instanceof GroupingDefinition)) {
852 throw new IllegalArgumentException("Failed to generate code for augment in " + u);
854 var gr = targetGrouping as GroupingDefinition;
855 result = gr.getDataChildByName(currentName);
\r
858 if (result == null) {
859 currentName = (parent as SchemaNode).QName.localName;
860 if (parent instanceof DataSchemaNode) {
861 parent = (parent as DataSchemaNode).parent;
863 parent = (parent as DataNodeContainer).parent;
866 } while (result == null && !(parent instanceof Module));
868 if (result != null) {
869 if (tmpPath.size == 1) {
872 var DataSchemaNode newParent = result;
873 Collections.reverse(tmpPath);
875 for (name : tmpPath) {
876 newParent = (newParent as DataNodeContainer).getDataChildByName(name);
887 * Convenient method to find node added by uses statement.
\r
889 private def DataSchemaNode findOriginalTargetFromGrouping(String targetSchemaNodeName, UsesNode parentUsesNode) {
890 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, parentUsesNode.groupingPath.path);
891 if (!(targetGrouping instanceof GroupingDefinition)) {
892 throw new IllegalArgumentException("Failed to generate code for augment in " + parentUsesNode);
895 var grouping = targetGrouping as GroupingDefinition;
896 var result = grouping.getDataChildByName(targetSchemaNodeName);
897 if (result == null) {
900 var boolean fromUses = result.addedByUses;
902 var Iterator<UsesNode> groupingUses = grouping.uses.iterator;
904 if (groupingUses.hasNext()) {
905 grouping = findNodeInSchemaContext(schemaContext, groupingUses.next().groupingPath.path) as GroupingDefinition;
906 result = grouping.getDataChildByName(targetSchemaNodeName);
907 fromUses = result.addedByUses;
909 throw new NullPointerException("Failed to generate code for augment in " + parentUsesNode);
917 * Returns a generated type builder for an augmentation.
\r
919 * The name of the type builder is equal to the name of augmented node with
\r
920 * serial number as suffix.
\r
922 * @param module current module
\r
923 * @param augmentPackageName
\r
924 * string with contains the package name to which the augment
\r
926 * @param basePackageName
\r
927 * string with the package name to which the augmented node
\r
929 * @param targetTypeRef
\r
932 * augmentation schema which contains data about the child nodes
\r
933 * and uses of augment
\r
934 * @return generated type builder for augment
\r
936 private def GeneratedTypeBuilder addRawAugmentGenTypeDefinition(Module module, String augmentPackageName,
937 String basePackageName, Type targetTypeRef, AugmentationSchema augSchema) {
938 var Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
939 if (augmentBuilders === null) {
940 augmentBuilders = new HashMap();
941 genTypeBuilders.put(augmentPackageName, augmentBuilders);
943 val augIdentifier = getAugmentIdentifier(augSchema.unknownSchemaNodes);
945 val augTypeName = if (augIdentifier !== null) {
946 parseToClassName(augIdentifier)
948 augGenTypeName(augmentBuilders, targetTypeRef.name);
951 val augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
953 augTypeBuilder.addImplementsType(DATA_OBJECT);
954 augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
955 addImplementedInterfaceFromUses(augSchema, augTypeBuilder);
957 augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema.childNodes);
958 augmentBuilders.put(augTypeName, augTypeBuilder);
959 return augTypeBuilder;
964 * @param unknownSchemaNodes
\r
965 * @return nodeParameter of UnknownSchemaNode
\r
967 private def String getAugmentIdentifier(List<UnknownSchemaNode> unknownSchemaNodes) {
968 for (unknownSchemaNode : unknownSchemaNodes) {
969 val nodeType = unknownSchemaNode.nodeType;
970 if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.localName) &&
971 YANG_EXT_NAMESPACE.equals(nodeType.namespace.toString())) {
972 return unknownSchemaNode.nodeParameter;
979 * Returns first unique name for the augment generated type builder. The
\r
980 * generated type builder name for augment consists from name of augmented
\r
981 * node and serial number of its augmentation.
\r
984 * map of builders which were created in the package to which the
\r
985 * augmentation belongs
\r
986 * @param genTypeName
\r
987 * string with name of augmented node
\r
988 * @return string with unique name for augmentation builder
\r
990 private def String augGenTypeName(Map<String, GeneratedTypeBuilder> builders, String genTypeName) {
992 while ((builders !== null) && builders.containsKey(genTypeName + index)) {
995 return genTypeName + index;
999 * Adds the methods to <code>typeBuilder</code> which represent subnodes of
\r
1000 * node for which <code>typeBuilder</code> was created.
\r
1002 * The subnodes aren't mapped to the methods if they are part of grouping or
\r
1003 * augment (in this case are already part of them).
\r
1005 * @param module current module
\r
1006 * @param basePackageName
\r
1007 * string contains the module package name
\r
1009 * generated type builder which represents any node. The subnodes
\r
1010 * of this node are added to the <code>typeBuilder</code> as
\r
1011 * methods. The subnode can be of type leaf, leaf-list, list,
\r
1012 * container, choice.
\r
1013 * @param childOf parent type
\r
1014 * @param schemaNodes
\r
1015 * set of data schema nodes which are the children of the node
\r
1016 * for which <code>typeBuilder</code> was created
\r
1017 * @return generated type builder which is the same builder as input
\r
1018 * parameter. The getter methods (representing child nodes) could be
\r
1021 private def GeneratedTypeBuilder resolveDataSchemaNodes(Module module, String basePackageName,
1022 GeneratedTypeBuilder parent, GeneratedTypeBuilder childOf, Set<DataSchemaNode> schemaNodes) {
1023 if ((schemaNodes !== null) && (parent !== null)) {
1024 for (schemaNode : schemaNodes) {
1025 if (!schemaNode.augmenting && !schemaNode.addedByUses) {
1026 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module);
1034 * Adds the methods to <code>typeBuilder</code> what represents subnodes of
\r
1035 * node for which <code>typeBuilder</code> was created.
\r
1037 * @param module current module
\r
1038 * @param basePackageName
\r
1039 * string contains the module package name
\r
1040 * @param typeBuilder
\r
1041 * generated type builder which represents any node. The subnodes
\r
1042 * of this node are added to the <code>typeBuilder</code> as
\r
1043 * methods. The subnode can be of type leaf, leaf-list, list,
\r
1044 * container, choice.
\r
1045 * @param childOf parent type
\r
1046 * @param schemaNodes
\r
1047 * set of data schema nodes which are the children of the node
\r
1048 * for which <code>typeBuilder</code> was created
\r
1049 * @return generated type builder which is the same object as the input
\r
1050 * parameter <code>typeBuilder</code>. The getter method could be
\r
1053 private def GeneratedTypeBuilder augSchemaNodeToMethods(Module module, String basePackageName,
1054 GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Set<DataSchemaNode> schemaNodes) {
1055 if ((schemaNodes !== null) && (typeBuilder !== null)) {
1056 for (schemaNode : schemaNodes) {
1057 if (!schemaNode.isAugmenting()) {
1058 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module);
1066 * Adds to <code>typeBuilder</code> a method which is derived from
\r
1067 * <code>schemaNode</code>.
\r
1069 * @param basePackageName
\r
1070 * string with the module package name
\r
1072 * data schema node which is added to <code>typeBuilder</code> as
\r
1074 * @param typeBuilder
\r
1075 * generated type builder to which is <code>schemaNode</code>
\r
1076 * added as a method.
\r
1077 * @param childOf parent type
\r
1078 * @param module current module
\r
1080 private def void addSchemaNodeToBuilderAsMethod(String basePackageName, DataSchemaNode node,
1081 GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Module module) {
1082 if (node !== null && typeBuilder !== null) {
1084 case node instanceof LeafSchemaNode:
1085 resolveLeafSchemaNodeAsMethod(typeBuilder, node as LeafSchemaNode)
1086 case node instanceof LeafListSchemaNode:
1087 resolveLeafListSchemaNode(typeBuilder, node as LeafListSchemaNode)
1088 case node instanceof ContainerSchemaNode:
1089 containerToGenType(module, basePackageName, typeBuilder, childOf, node as ContainerSchemaNode)
1090 case node instanceof ListSchemaNode:
1091 listToGenType(module, basePackageName, typeBuilder, childOf, node as ListSchemaNode)
1092 case node instanceof ChoiceNode:
1093 choiceToGeneratedType(module, basePackageName, typeBuilder, node as ChoiceNode)
1099 * Converts <code>choiceNode</code> to the list of generated types for
\r
1100 * choice and its cases.
\r
1102 * The package names for choice and for its cases are created as
\r
1103 * concatenation of the module package (<code>basePackageName</code>) and
\r
1104 * names of all parents node.
\r
1106 * @param module current module
\r
1107 * @param basePackageName
\r
1108 * string with the module package name
\r
1109 * @param parent parent type
\r
1110 * @param childOf concrete parent for case child nodes
\r
1111 * @param choiceNode
\r
1112 * choice node which is mapped to generated type. Also child
\r
1113 * nodes - cases are mapped to generated types.
\r
1114 * @throws IllegalArgumentException
\r
1116 * <li>if <code>basePackageName</code> equals null</li>
\r
1117 * <li>if <code>choiceNode</code> equals null</li>
\r
1121 private def void choiceToGeneratedType(Module module, String basePackageName, GeneratedTypeBuilder parent,
1122 ChoiceNode choiceNode) {
1123 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1124 checkArgument(choiceNode !== null, "Choice Schema Node cannot be NULL.");
1126 val packageName = packageNameForGeneratedType(basePackageName, choiceNode.path);
1127 val choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
1128 constructGetter(parent, choiceNode.QName.localName, choiceNode.description, choiceTypeBuilder);
1129 choiceTypeBuilder.addImplementsType(DataContainer.typeForClass);
1130 genCtx.get(module).addChildNodeType(choiceNode.path, choiceTypeBuilder)
1131 generateTypesFromChoiceCases(module, basePackageName, parent, choiceTypeBuilder.toInstance, choiceNode);
1135 * Converts <code>caseNodes</code> set to list of corresponding generated
\r
1138 * For every <i>case</i> which isn't added through augment or <i>uses</i> is
\r
1139 * created generated type builder. The package names for the builder is
\r
1140 * created as concatenation of the module package (
\r
1141 * <code>basePackageName</code>) and names of all parents nodes of the
\r
1142 * concrete <i>case</i>. There is also relation "<i>implements type</i>"
\r
1143 * between every case builder and <i>choice</i> type
\r
1145 * @param basePackageName
\r
1146 * string with the module package name
\r
1147 * @param refChoiceType
\r
1148 * type which represents superior <i>case</i>
\r
1149 * @param caseNodes
\r
1150 * set of choice case nodes which are mapped to generated types
\r
1151 * @return list of generated types for <code>caseNodes</code>.
\r
1152 * @throws IllegalArgumentException
\r
1154 * <li>if <code>basePackageName</code> equals null</li>
\r
1155 * <li>if <code>refChoiceType</code> equals null</li>
\r
1156 * <li>if <code>caseNodes</code> equals null</li>
\r
1160 private def void generateTypesFromChoiceCases(Module module, String basePackageName,
1161 GeneratedTypeBuilder choiceParent, Type refChoiceType, ChoiceNode choiceNode) {
1162 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1163 checkArgument(refChoiceType !== null, "Referenced Choice Type cannot be NULL.");
1164 checkArgument(choiceNode !== null, "ChoiceNode cannot be NULL.");
1166 val Set<ChoiceCaseNode> caseNodes = choiceNode.cases;
1167 if (caseNodes == null) {
1171 for (caseNode : caseNodes) {
1172 if (caseNode !== null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
1173 val packageName = packageNameForGeneratedType(basePackageName, caseNode.path);
1174 val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
1175 caseTypeBuilder.addImplementsType(refChoiceType);
1176 genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder)
1177 val Set<DataSchemaNode> caseChildNodes = caseNode.childNodes;
1178 if (caseChildNodes !== null) {
1179 val parentNode = choiceNode.parent;
1180 var SchemaNode parent;
1181 if (parentNode instanceof AugmentationSchema) {
1182 val augSchema = parentNode as AugmentationSchema;
1183 val targetPath = augSchema.targetPath;
1184 var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
1185 if (targetSchemaNode instanceof DataSchemaNode &&
1186 (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
1187 targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
1188 if (targetSchemaNode == null) {
1189 throw new NullPointerException(
1190 "Failed to find target node from grouping for augmentation " + augSchema +
1191 " in module " + module.name);
1194 parent = targetSchemaNode as SchemaNode
1196 parent = choiceNode.parent as SchemaNode;
1198 var GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.path)
1199 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes);
1203 processUsesAugments(caseNode, module);
1208 * Generates list of generated types for all the cases of a choice which are
\r
1209 * added to the choice through the augment.
\r
1212 * @param basePackageName
\r
1213 * string contains name of package to which augment belongs. If
\r
1214 * an augmented choice is from an other package (pcg1) than an
\r
1215 * augmenting choice (pcg2) then case's of the augmenting choice
\r
1216 * will belong to pcg2.
\r
1217 * @param refChoiceType
\r
1218 * Type which represents the choice to which case belongs. Every
\r
1219 * case has to contain its choice in extend part.
\r
1220 * @param caseNodes
\r
1221 * set of choice case nodes for which is checked if are/aren't
\r
1222 * added to choice through augmentation
\r
1223 * @return list of generated types which represents augmented cases of
\r
1224 * choice <code>refChoiceType</code>
\r
1225 * @throws IllegalArgumentException
\r
1227 * <li>if <code>basePackageName</code> equals null</li>
\r
1228 * <li>if <code>refChoiceType</code> equals null</li>
\r
1229 * <li>if <code>caseNodes</code> equals null</li>
\r
1232 private def void generateTypesFromAugmentedChoiceCases(Module module, String basePackageName, Type targetType,
1233 ChoiceNode targetNode, Set<DataSchemaNode> augmentedNodes) {
1234 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1235 checkArgument(targetType !== null, "Referenced Choice Type cannot be NULL.");
1236 checkArgument(augmentedNodes !== null, "Set of Choice Case Nodes cannot be NULL.");
1238 for (caseNode : augmentedNodes) {
1239 if (caseNode !== null) {
1240 val packageName = packageNameForGeneratedType(basePackageName, caseNode.path);
1241 val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
1242 caseTypeBuilder.addImplementsType(targetType);
1244 val SchemaNode parent = targetNode.parent as SchemaNode;
1245 var GeneratedTypeBuilder childOfType = null;
1246 if (parent instanceof Module) {
1247 childOfType = genCtx.get(parent as Module).moduleNode
1248 } else if (parent instanceof ChoiceCaseNode) {
1249 childOfType = findCaseByPath(parent.path)
1250 } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) {
1251 childOfType = findChildNodeByPath(parent.path)
1252 } else if (parent instanceof GroupingDefinition) {
1253 childOfType = findGroupingByPath(parent.path);
1256 if (childOfType == null) {
1257 throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode);
1260 if (caseNode instanceof DataNodeContainer) {
1261 val DataNodeContainer dataNodeCase = caseNode as DataNodeContainer;
1262 val Set<DataSchemaNode> childNodes = dataNodeCase.childNodes;
1263 if (childNodes !== null) {
1264 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
1267 val ChoiceCaseNode node = targetNode.getCaseNodeByName(caseNode.getQName().getLocalName());
1268 val Set<DataSchemaNode> childNodes = node.childNodes;
1269 if (childNodes !== null) {
1270 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
1274 genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder)
1281 * Converts <code>leaf</code> to the getter method which is added to
\r
1282 * <code>typeBuilder</code>.
\r
1284 * @param typeBuilder
\r
1285 * generated type builder to which is added getter method as
\r
1286 * <code>leaf</code> mapping
\r
1288 * leaf schema node which is mapped as getter method which is
\r
1289 * added to <code>typeBuilder</code>
\r
1290 * @return boolean value
\r
1292 * <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
\r
1294 * <li>true - in other cases</li>
\r
1297 private def boolean resolveLeafSchemaNodeAsMethod(GeneratedTypeBuilder typeBuilder, LeafSchemaNode leaf) {
1298 if ((leaf !== null) && (typeBuilder !== null)) {
1299 val leafName = leaf.QName.localName;
1300 var String leafDesc = leaf.description;
1301 if (leafDesc === null) {
1305 val parentModule = findParentModule(schemaContext, leaf);
1306 if (leafName !== null && !leaf.isAddedByUses()) {
1307 val TypeDefinition<?> typeDef = leaf.type;
1309 var Type returnType = null;
1310 if (typeDef instanceof EnumTypeDefinition) {
1311 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
1312 val enumTypeDef = typeDef as EnumTypeDefinition;
1313 val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leafName, typeBuilder);
1315 if (enumBuilder !== null) {
1316 returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name);
1318 (typeProvider as TypeProviderImpl).putReferencedType(leaf.path, returnType);
1319 } else if (typeDef instanceof UnionType) {
1320 val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
1321 if (genTOBuilder !== null) {
1322 returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
1324 } else if (typeDef instanceof BitsTypeDefinition) {
1325 val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
1326 if (genTOBuilder !== null) {
1327 returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
1330 val Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
\r
1331 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
1333 if (returnType !== null) {
1334 val MethodSignatureBuilder getter = constructGetter(typeBuilder, leafName, leafDesc, returnType);
1335 processContextRefExtension(leaf, getter, parentModule);
1343 private def void processContextRefExtension(LeafSchemaNode leaf, MethodSignatureBuilder getter, Module module) {
1344 for (node : leaf.unknownSchemaNodes) {
1345 val nodeType = node.nodeType;
1346 if ("context-reference".equals(nodeType.localName)) {
1347 val nodeParam = node.nodeParameter;
1348 var IdentitySchemaNode identity = null;
1349 var String basePackageName = null;
1350 val String[] splittedElement = nodeParam.split(":");
1351 if (splittedElement.length == 1) {
1352 identity = findIdentityByName(module.identities, splittedElement.get(0));
1353 basePackageName = moduleNamespaceToPackageName(module);
1354 } else if (splittedElement.length == 2) {
1355 var prefix = splittedElement.get(0);
1356 val Module dependentModule = findModuleFromImports(module.imports, prefix)
1357 if (dependentModule == null) {
1358 throw new IllegalArgumentException(
1359 "Failed to process context-reference: unknown prefix " + prefix);
1361 identity = findIdentityByName(dependentModule.identities, splittedElement.get(1));
1362 basePackageName = moduleNamespaceToPackageName(dependentModule);
1364 throw new IllegalArgumentException(
1365 "Failed to process context-reference: unknown identity " + nodeParam);
1367 if (identity == null) {
1368 throw new IllegalArgumentException(
1369 "Failed to process context-reference: unknown identity " + nodeParam);
1372 val Class<RoutingContext> clazz = typeof(RoutingContext);
1373 val AnnotationTypeBuilder rc = getter.addAnnotation(clazz.package.name, clazz.simpleName);
1374 val packageName = packageNameForGeneratedType(basePackageName, identity.path);
1375 val genTypeName = parseToClassName(identity.QName.localName);
1376 rc.addParameter("value", packageName + "." + genTypeName + ".class");
1381 private def IdentitySchemaNode findIdentityByName(Set<IdentitySchemaNode> identities, String name) {
1382 for (id : identities) {
1383 if (id.QName.localName.equals(name)) {
1390 private def Module findModuleFromImports(Set<ModuleImport> imports, String prefix) {
1391 for (imp : imports) {
1392 if (imp.prefix.equals(prefix)) {
1393 return schemaContext.findModuleByName(imp.moduleName, imp.revision);
1400 * Converts <code>leaf</code> schema node to property of generated TO
\r
1403 * @param toBuilder
\r
1404 * generated TO builder to which is <code>leaf</code> added as
\r
1407 * leaf schema node which is added to <code>toBuilder</code> as
\r
1409 * @param isReadOnly
\r
1410 * boolean value which says if leaf property is|isn't read only
\r
1411 * @return boolean value
\r
1413 * <li>false - if <code>leaf</code>, <code>toBuilder</code> or leaf
\r
1414 * name equals null or if leaf is added by <i>uses</i>.</li>
\r
1415 * <li>true - other cases</li>
\r
1418 private def boolean resolveLeafSchemaNodeAsProperty(GeneratedTOBuilder toBuilder, LeafSchemaNode leaf,
1419 boolean isReadOnly) {
1420 if ((leaf !== null) && (toBuilder !== null)) {
1421 val leafName = leaf.QName.localName;
1422 var String leafDesc = leaf.description;
1423 if (leafDesc === null) {
1427 if (leafName !== null) {
1428 val TypeDefinition<?> typeDef = leaf.type;
1430 // TODO: properly resolve enum types
\r
1431 val returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
1433 if (returnType !== null) {
1434 val propBuilder = toBuilder.addProperty(parseToClassName(leafName));
1436 propBuilder.setReadOnly(isReadOnly);
1437 propBuilder.setReturnType(returnType);
1438 propBuilder.setComment(leafDesc);
1440 toBuilder.addEqualsIdentity(propBuilder);
1441 toBuilder.addHashIdentity(propBuilder);
1442 toBuilder.addToStringProperty(propBuilder);
1452 * Converts <code>node</code> leaf list schema node to getter method of
\r
1453 * <code>typeBuilder</code>.
\r
1455 * @param typeBuilder
\r
1456 * generated type builder to which is <code>node</code> added as
\r
1459 * leaf list schema node which is added to
\r
1460 * <code>typeBuilder</code> as getter method
\r
1461 * @return boolean value
\r
1463 * <li>true - if <code>node</code>, <code>typeBuilder</code>,
\r
1464 * nodeName equal null or <code>node</code> is added by <i>uses</i></li>
\r
1465 * <li>false - other cases</li>
\r
1468 private def boolean resolveLeafListSchemaNode(GeneratedTypeBuilder typeBuilder, LeafListSchemaNode node) {
1469 if ((node !== null) && (typeBuilder !== null)) {
1470 val nodeName = node.QName.localName;
1471 var String nodeDesc = node.description;
1472 if (nodeDesc === null) {
1475 if (nodeName !== null && !node.isAddedByUses()) {
1476 val TypeDefinition<?> type = node.type;
1477 val listType = Types.listTypeFor(typeProvider.javaTypeForSchemaDefinitionType(type, node));
1478 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
1485 private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode) {
1486 return addDefaultInterfaceDefinition(packageName, schemaNode, null);
1490 * Instantiates generated type builder with <code>packageName</code> and
\r
1491 * <code>schemaNode</code>.
\r
1493 * The new builder always implements
\r
1494 * {@link org.opendaylight.yangtools.yang.binding.DataObject DataObject}.<br />
\r
1495 * If <code>schemaNode</code> is instance of GroupingDefinition it also
\r
1496 * implements {@link org.opendaylight.yangtools.yang.binding.Augmentable
\r
1497 * Augmentable}.<br />
\r
1498 * If <code>schemaNode</code> is instance of
\r
1499 * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
\r
1500 * DataNodeContainer} it can also implement nodes which are specified in
\r
1503 * @param packageName
\r
1504 * string with the name of the package to which
\r
1505 * <code>schemaNode</code> belongs.
\r
1506 * @param schemaNode
\r
1507 * schema node for which is created generated type builder
\r
1508 * @param parent parent type (can be null)
\r
1509 * @return generated type builder <code>schemaNode</code>
\r
1511 private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode,
1513 val builder = addRawInterfaceDefinition(packageName, schemaNode, "");
1514 if (parent === null) {
1515 builder.addImplementsType(DATA_OBJECT);
1517 builder.addImplementsType(BindingTypes.childOf(parent));
1519 if (!(schemaNode instanceof GroupingDefinition)) {
1520 builder.addImplementsType(augmentable(builder));
1523 if (schemaNode instanceof DataNodeContainer) {
1524 addImplementedInterfaceFromUses(schemaNode as DataNodeContainer, builder);
1531 * Wraps the calling of the same overloaded method.
\r
1533 * @param packageName
\r
1534 * string with the package name to which returning generated type
\r
1536 * @param schemaNode
\r
1537 * schema node which provide data about the schema node name
\r
1538 * @return generated type builder for <code>schemaNode</code>
\r
1540 private def GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode) {
1541 return addRawInterfaceDefinition(packageName, schemaNode, "");
1545 * Returns reference to generated type builder for specified
\r
1546 * <code>schemaNode</code> with <code>packageName</code>.
\r
1548 * Firstly the generated type builder is searched in
\r
1549 * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
\r
1550 * found it is created and added to <code>genTypeBuilders</code>.
\r
1552 * @param packageName
\r
1553 * string with the package name to which returning generated type
\r
1555 * @param schemaNode
\r
1556 * schema node which provide data about the schema node name
\r
1557 * @param prefix return type name prefix
\r
1558 * @return generated type builder for <code>schemaNode</code>
\r
1559 * @throws IllegalArgumentException
\r
1561 * <li>if <code>schemaNode</code> equals null</li>
\r
1562 * <li>if <code>packageName</code> equals null</li>
\r
1563 * <li>if Q name of schema node is null</li>
\r
1564 * <li>if schema node name is nul</li>
\r
1568 private def GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode,
1570 checkArgument(schemaNode !== null, "Data Schema Node cannot be NULL.");
1571 checkArgument(packageName !== null, "Package Name for Generated Type cannot be NULL.");
1572 checkArgument(schemaNode.QName !== null, "QName for Data Schema Node cannot be NULL.");
1573 val schemaNodeName = schemaNode.QName.localName;
1574 checkArgument(schemaNodeName !== null, "Local Name of QName for Data Schema Node cannot be NULL.");
1576 var String genTypeName;
1577 if (prefix === null) {
1578 genTypeName = parseToClassName(schemaNodeName);
1580 genTypeName = prefix + parseToClassName(schemaNodeName);
1583 //FIXME: Validation of name conflict
\r
1584 val newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
1585 if (!genTypeBuilders.containsKey(packageName)) {
1586 val Map<String, GeneratedTypeBuilder> builders = new HashMap();
1587 builders.put(genTypeName, newType);
1588 genTypeBuilders.put(packageName, builders);
1590 val Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
1591 if (!builders.containsKey(genTypeName)) {
1592 builders.put(genTypeName, newType);
1599 * Creates the name of the getter method from <code>methodName</code>.
\r
1601 * @param methodName
\r
1602 * string with the name of the getter method
\r
1603 * @param returnType return type
\r
1604 * @return string with the name of the getter method for
\r
1605 * <code>methodName</code> in JAVA method format
\r
1607 private def String getterMethodName(String methodName, Type returnType) {
1608 val method = new StringBuilder();
1609 if (BOOLEAN.equals(returnType)) {
1610 method.append("is");
1612 method.append("get");
1614 method.append(parseToClassName(methodName));
1615 return method.toString();
1619 * Created a method signature builder as part of
\r
1620 * <code>interfaceBuilder</code>.
\r
1622 * The method signature builder is created for the getter method of
\r
1623 * <code>schemaNodeName</code>. Also <code>comment</code> and
\r
1624 * <code>returnType</code> information are added to the builder.
\r
1626 * @param interfaceBuilder
\r
1627 * generated type builder for which the getter method should be
\r
1629 * @param schemaNodeName
\r
1630 * string with schema node name. The name will be the part of the
\r
1631 * getter method name.
\r
1633 * string with comment for the getter method
\r
1634 * @param returnType
\r
1635 * type which represents the return type of the getter method
\r
1636 * @return method signature builder which represents the getter method of
\r
1637 * <code>interfaceBuilder</code>
\r
1639 private def MethodSignatureBuilder constructGetter(GeneratedTypeBuilder interfaceBuilder, String schemaNodeName,
1640 String comment, Type returnType) {
1641 val getMethod = interfaceBuilder.addMethod(getterMethodName(schemaNodeName, returnType));
1642 getMethod.setComment(comment);
1643 getMethod.setReturnType(returnType);
1648 * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
\r
1649 * or to <code>genTOBuilder</code> as property.
\r
1651 * @param basePackageName
\r
1652 * string contains the module package name
\r
1653 * @param schemaNode
\r
1654 * data schema node which should be added as getter method to
\r
1655 * <code>typeBuilder</code> or as a property to
\r
1656 * <code>genTOBuilder</code> if is part of the list key
\r
1657 * @param typeBuilder
\r
1658 * generated type builder for the list schema node
\r
1659 * @param genTOBuilder
\r
1660 * generated TO builder for the list keys
\r
1662 * list of string which contains names of the list keys
\r
1663 * @param module current module
\r
1664 * @throws IllegalArgumentException
\r
1666 * <li>if <code>schemaNode</code> equals null</li>
\r
1667 * <li>if <code>typeBuilder</code> equals null</li>
\r
1670 private def void addSchemaNodeToListBuilders(String basePackageName, DataSchemaNode schemaNode,
1671 GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder, List<String> listKeys, Module module) {
1672 checkArgument(schemaNode !== null, "Data Schema Node cannot be NULL.");
1673 checkArgument(typeBuilder !== null, "Generated Type Builder cannot be NULL.");
1675 if (schemaNode instanceof LeafSchemaNode) {
1676 val leaf = schemaNode as LeafSchemaNode;
1677 val leafName = leaf.QName.localName;
1678 if (!listKeys.contains(leafName)) {
1679 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
1681 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
1683 } else if (!schemaNode.addedByUses) {
1684 if (schemaNode instanceof LeafListSchemaNode) {
1685 resolveLeafListSchemaNode(typeBuilder, schemaNode as LeafListSchemaNode);
1686 } else if (schemaNode instanceof ContainerSchemaNode) {
1687 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, schemaNode as ContainerSchemaNode);
1688 } else if (schemaNode instanceof ChoiceNode) {
1689 choiceToGeneratedType(module, basePackageName, typeBuilder, schemaNode as ChoiceNode);
1690 } else if (schemaNode instanceof ListSchemaNode) {
1691 listToGenType(module, basePackageName, typeBuilder, typeBuilder, schemaNode as ListSchemaNode);
1696 private def typeBuildersToGenTypes(Module module, GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder) {
1697 checkArgument(typeBuilder !== null, "Generated Type Builder cannot be NULL.");
1699 if (genTOBuilder !== null) {
1700 val genTO = genTOBuilder.toInstance();
1701 constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO);
1702 genCtx.get(module).addGeneratedTOBuilder(genTOBuilder)
1707 * Selects the names of the list keys from <code>list</code> and returns
\r
1708 * them as the list of the strings
\r
1711 * of string with names of the list keys
\r
1712 * @return list of string which represents names of the list keys. If the
\r
1713 * <code>list</code> contains no keys then the empty list is
\r
1716 private def listKeys(ListSchemaNode list) {
1717 val List<String> listKeys = new ArrayList();
1719 if (list.keyDefinition !== null) {
1720 val keyDefinitions = list.keyDefinition;
1721 for (keyDefinition : keyDefinitions) {
1722 listKeys.add(keyDefinition.localName);
1729 * Generates for the <code>list</code> which contains any list keys special
\r
1730 * generated TO builder.
\r
1732 * @param packageName
\r
1733 * string with package name to which the list belongs
\r
1735 * list schema node which is source of data about the list name
\r
1736 * @return generated TO builder which represents the keys of the
\r
1737 * <code>list</code> or null if <code>list</code> is null or list of
\r
1738 * key definitions is null or empty.
\r
1740 private def GeneratedTOBuilder resolveListKeyTOBuilder(String packageName, ListSchemaNode list) {
1741 var GeneratedTOBuilder genTOBuilder = null;
1742 if ((list.keyDefinition !== null) && (!list.keyDefinition.isEmpty())) {
1743 if (list !== null) {
1744 val listName = list.QName.localName + "Key";
1745 val String genTOName = parseToClassName(listName);
1746 genTOBuilder = new GeneratedTOBuilderImpl(packageName, genTOName);
1749 return genTOBuilder;
1753 * Builds generated TO builders for <code>typeDef</code> of type
\r
1754 * {@link org.opendaylight.yangtools.yang.model.util.UnionType UnionType} or
\r
1755 * {@link org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
\r
1756 * BitsTypeDefinition} which are also added to <code>typeBuilder</code> as
\r
1757 * enclosing transfer object.
\r
1759 * If more then one generated TO builder is created for enclosing then all
\r
1760 * of the generated TO builders are added to <code>typeBuilder</code> as
\r
1761 * enclosing transfer objects.
\r
1764 * type definition which can be of type <code>UnionType</code> or
\r
1765 * <code>BitsTypeDefinition</code>
\r
1766 * @param typeBuilder
\r
1767 * generated type builder to which is added generated TO created
\r
1768 * from <code>typeDef</code>
\r
1770 * string with name for generated TO builder
\r
1772 * @param parentModule
\r
1773 * @return generated TO builder for <code>typeDef</code>
\r
1775 private def GeneratedTOBuilder addTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
1776 String leafName, LeafSchemaNode leaf, Module parentModule) {
1777 val classNameFromLeaf = parseToClassName(leafName);
1778 val List<GeneratedTOBuilder> genTOBuilders = new ArrayList();
1779 val packageName = typeBuilder.fullyQualifiedName;
1780 if (typeDef instanceof UnionTypeDefinition) {
1781 genTOBuilders.addAll(
1782 (typeProvider as TypeProviderImpl).
1783 provideGeneratedTOBuildersForUnionTypeDef(packageName, (typeDef as UnionTypeDefinition),
1784 classNameFromLeaf, leaf));
1785 } else if (typeDef instanceof BitsTypeDefinition) {
1787 ((typeProvider as TypeProviderImpl) ).
1788 provideGeneratedTOBuilderForBitsTypeDefinition(packageName, typeDef, classNameFromLeaf));
1790 if (genTOBuilders !== null && !genTOBuilders.isEmpty()) {
1791 for (genTOBuilder : genTOBuilders) {
1792 typeBuilder.addEnclosingTransferObject(genTOBuilder);
1794 return genTOBuilders.get(0);
1801 * Adds the implemented types to type builder.
\r
1803 * The method passes through the list of <i>uses</i> in
\r
1804 * {@code dataNodeContainer}. For every <i>use</i> is obtained coresponding
\r
1805 * generated type from {@link BindingGeneratorImpl#allGroupings
\r
1806 * allGroupings} which is added as <i>implements type</i> to
\r
1807 * <code>builder</code>
\r
1809 * @param dataNodeContainer
\r
1810 * element which contains the list of used YANG groupings
\r
1812 * builder to which are added implemented types according to
\r
1813 * <code>dataNodeContainer</code>
\r
1814 * @return generated type builder with all implemented types
\r
1816 private def addImplementedInterfaceFromUses(DataNodeContainer dataNodeContainer, GeneratedTypeBuilder builder) {
1817 for (usesNode : dataNodeContainer.uses) {
1818 if (usesNode.groupingPath !== null) {
1819 val genType = findGroupingByPath(usesNode.groupingPath).toInstance
1820 if (genType === null) {
1821 throw new IllegalStateException(
1822 "Grouping " + usesNode.groupingPath + "is not resolved for " + builder.name);
1824 builder.addImplementsType(genType);
1830 private def GeneratedTypeBuilder findChildNodeByPath(SchemaPath path) {
1831 for (ctx : genCtx.values) {
1832 var result = ctx.getChildNode(path)
1833 if (result !== null) {
1840 private def GeneratedTypeBuilder findGroupingByPath(SchemaPath path) {
1841 for (ctx : genCtx.values) {
1842 var result = ctx.getGrouping(path)
1843 if (result !== null) {
1850 private def GeneratedTypeBuilder findCaseByPath(SchemaPath path) {
1851 for (ctx : genCtx.values) {
1852 var result = ctx.getCase(path)
1853 if (result !== null) {