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
75 public class BindingGeneratorImpl implements BindingGenerator {
77 private final Map<Module, ModuleContext> genCtx = new HashMap()
80 * Outter key represents the package name. Outter value represents map of
\r
81 * all builders in the same package. Inner key represents the schema node
\r
82 * name (in JAVA class/interface name format). Inner value represents
\r
83 * instance of builder for schema node specified in key part.
\r
85 private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
88 * Provide methods for converting YANG types to JAVA types.
\r
90 private var TypeProvider typeProvider;
93 * Holds reference to schema context to resolve data of augmented elemnt
\r
94 * when creating augmentation builder
\r
96 private var SchemaContext schemaContext;
99 * Constant with the concrete name of namespace.
\r
101 private val static String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
104 * Constant with the concrete name of identifier.
\r
106 private val static String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
109 * Resolves generated types from <code>context</code> schema nodes of all
\r
112 * Generated types are created for modules, groupings, types, containers,
\r
113 * lists, choices, augments, rpcs, notification, identities.
\r
116 * schema context which contains data about all schema nodes
\r
118 * @return list of types (usually <code>GeneratedType</code>
\r
119 * <code>GeneratedTransferObject</code>which are generated from
\r
120 * <code>context</code> data.
\r
121 * @throws IllegalArgumentException
\r
122 * if param <code>context</code> is null
\r
123 * @throws IllegalStateException
\r
124 * if <code>context</code> contain no modules
\r
126 override generateTypes(SchemaContext context) {
127 checkArgument(context !== null, "Schema Context reference cannot be NULL.");
128 checkState(context.modules !== null, "Schema Context does not contain defined modules.");
129 schemaContext = context;
130 typeProvider = new TypeProviderImpl(context);
131 val Set<Module> modules = context.modules;
132 return generateTypes(context, modules);
136 * Resolves generated types from <code>context</code> schema nodes only for
\r
137 * modules specified in <code>modules</code>
\r
139 * Generated types are created for modules, groupings, types, containers,
\r
140 * lists, choices, augments, rpcs, notification, identities.
\r
143 * schema context which contains data about all schema nodes
\r
146 * set of modules for which schema nodes should be generated
\r
148 * @return list of types (usually <code>GeneratedType</code> or
\r
149 * <code>GeneratedTransferObject</code>) which:
\r
151 * <li>are generated from <code>context</code> schema nodes and</li>
\r
152 * <li>are also part of some of the module in <code>modules</code>
\r
155 * @throws IllegalArgumentException
\r
157 * <li>if param <code>context</code> is null or</li>
\r
158 * <li>if param <code>modules</code> is null</li>
\r
160 * @throws IllegalStateException
\r
161 * if <code>context</code> contain no modules
\r
163 override generateTypes(SchemaContext context, Set<Module> modules) {
164 checkArgument(context !== null, "Schema Context reference cannot be NULL.");
165 checkState(context.modules !== null, "Schema Context does not contain defined modules.");
166 checkArgument(modules !== null, "Set of Modules cannot be NULL.");
168 schemaContext = context;
169 typeProvider = new TypeProviderImpl(context);
170 val contextModules = ModuleDependencySort.sort(context.modules);
171 genTypeBuilders = new HashMap();
173 for (contextModule : contextModules) {
174 moduleToGenTypes(contextModule, context);
176 for (contextModule : contextModules) {
177 allAugmentsToGenTypes(contextModule);
180 val List<Type> filteredGenTypes = new ArrayList();
181 for (Module m : modules) {
182 filteredGenTypes.addAll(genCtx.get(m).generatedTypes);
187 return filteredGenTypes;
190 private def void moduleToGenTypes(Module m, SchemaContext context) {
191 genCtx.put(m, new ModuleContext)
192 allTypeDefinitionsToGenTypes(m)
193 groupingsToGenTypes(m, m.groupings)
194 rpcMethodsToGenType(m)
195 allIdentitiesToGenTypes(m, context)
196 notificationsToGenType(m)
198 if (!m.childNodes.isEmpty()) {
199 val moduleType = moduleToDataType(m)
200 genCtx.get(m).addModuleNode(moduleType)
201 val basePackageName = moduleNamespaceToPackageName(m);
202 resolveDataSchemaNodes(m, basePackageName, moduleType, moduleType, m.childNodes)
207 * Converts all extended type definitions of module to the list of
\r
208 * <code>Type</code> objects.
\r
211 * module from which is obtained set of type definitions
\r
212 * @throws IllegalArgumentException
\r
214 * <li>if module equals null</li>
\r
215 * <li>if name of module equals null</li>
\r
216 * <li>if type definitions of module equal null</li>
\r
220 private def void allTypeDefinitionsToGenTypes(Module module) {
221 checkArgument(module !== null, "Module reference cannot be NULL.");
222 checkArgument(module.name !== null, "Module name cannot be NULL.");
223 val it = new DataNodeIterator(module);
224 val List<TypeDefinition<?>> typeDefinitions = it.allTypedefs;
225 checkState(typeDefinitions !== null, '''Type Definitions for module «module.name» cannot be NULL.''');
227 for (TypeDefinition<?> typedef : typeDefinitions) {
228 if (typedef !== null) {
229 val type = (typeProvider as TypeProviderImpl).generatedTypeForExtendedDefinitionType(typedef, typedef);
231 genCtx.get(module).addTypedefType(typedef.path, type)
237 private def void containerToGenType(Module module, String basePackageName, GeneratedTypeBuilder parent,
238 GeneratedTypeBuilder childOf, ContainerSchemaNode node) {
239 if (node.augmenting || node.addedByUses) {
242 val packageName = packageNameForGeneratedType(basePackageName, node.path)
243 val genType = addDefaultInterfaceDefinition(packageName, node, childOf)
244 constructGetter(parent, node.QName.localName, node.description, genType)
245 genCtx.get(module).addChildNodeType(node.path, genType)
246 resolveDataSchemaNodes(module, basePackageName, genType, genType, node.childNodes)
247 groupingsToGenTypes(module, node.groupings)
248 processUsesAugments(node, module)
251 private def void listToGenType(Module module, String basePackageName, GeneratedTypeBuilder parent,
252 GeneratedTypeBuilder childOf, ListSchemaNode node) {
253 if (node.augmenting || node.addedByUses) {
256 val packageName = packageNameForGeneratedType(basePackageName, (node).path)
257 val genType = addDefaultInterfaceDefinition(packageName, node, childOf)
258 constructGetter(parent, node.QName.localName, node.description, Types.listTypeFor(genType))
259 genCtx.get(module).addChildNodeType(node.path, genType)
260 groupingsToGenTypes(module, node.groupings)
261 processUsesAugments(node, module)
263 val List<String> listKeys = listKeys(node);
264 val genTOBuilder = resolveListKeyTOBuilder(packageName, node);
266 if (genTOBuilder !== null) {
267 val identifierMarker = IDENTIFIER.parameterizedTypeFor(genType);
268 val identifiableMarker = IDENTIFIABLE.parameterizedTypeFor(genTOBuilder);
269 genTOBuilder.addImplementsType(identifierMarker);
270 genType.addImplementsType(identifiableMarker);
273 for (schemaNode : node.childNodes) {
274 if (!schemaNode.augmenting) {
275 addSchemaNodeToListBuilders(basePackageName, schemaNode, genType, genTOBuilder, listKeys, module);
279 typeBuildersToGenTypes(module, genType, genTOBuilder);
282 private def void processUsesAugments(DataNodeContainer node, Module module) {
283 val basePackageName = moduleNamespaceToPackageName(module);
284 for (usesNode : node.uses) {
285 for (augment : usesNode.augmentations) {
286 augmentationToGenTypes(basePackageName, augment, module, usesNode);
287 processUsesAugments(augment, module);
293 * Converts all <b>augmentation</b> of the module to the list
\r
294 * <code>Type</code> objects.
\r
297 * module from which is obtained list of all augmentation objects
\r
298 * to iterate over them
\r
299 * @throws IllegalArgumentException
\r
301 * <li>if the module equals null</li>
\r
302 * <li>if the name of module equals null</li>
\r
303 * <li>if the set of child nodes equals null</li>
\r
307 private def void allAugmentsToGenTypes(Module module) {
308 checkArgument(module !== null, "Module reference cannot be NULL.");
309 checkArgument(module.name !== null, "Module name cannot be NULL.");
310 if (module.childNodes === null) {
311 throw new IllegalArgumentException(
312 "Reference to Set of Augmentation Definitions in module " + module.name + " cannot be NULL.");
315 val basePackageName = moduleNamespaceToPackageName(module);
316 val List<AugmentationSchema> augmentations = resolveAugmentations(module);
317 for (augment : augmentations) {
318 augmentationToGenTypes(basePackageName, augment, module, null);
323 * Returns list of <code>AugmentationSchema</code> objects. The objects are
\r
324 * sorted according to the length of their target path from the shortest to
\r
328 * module from which is obtained list of all augmentation objects
\r
329 * @return list of sorted <code>AugmentationSchema</code> objects obtained
\r
330 * from <code>module</code>
\r
331 * @throws IllegalArgumentException
\r
333 * <li>if the module equals null</li>
\r
334 * <li>if the set of augmentation equals null</li>
\r
338 private def List<AugmentationSchema> resolveAugmentations(Module module) {
339 checkArgument(module !== null, "Module reference cannot be NULL.");
340 checkState(module.augmentations !== null, "Augmentations Set cannot be NULL.");
342 val Set<AugmentationSchema> augmentations = module.augmentations;
343 val List<AugmentationSchema> sortedAugmentations = new ArrayList(augmentations);
344 Collections.sort(sortedAugmentations,
345 [ augSchema1, augSchema2 |
346 if (augSchema1.targetPath.path.size() > augSchema2.targetPath.path.size()) {
348 } else if (augSchema1.targetPath.path.size() < augSchema2.targetPath.path.size()) {
353 return sortedAugmentations;
357 * Converts whole <b>module</b> to <code>GeneratedType</code> object.
\r
358 * Firstly is created the module builder object from which is vally
\r
359 * obtained reference to <code>GeneratedType</code> object.
\r
362 * module from which are obtained the module name, child nodes,
\r
363 * uses and is derived package name
\r
364 * @return <code>GeneratedType</code> which is internal representation of
\r
366 * @throws IllegalArgumentException
\r
367 * if the module equals null
\r
370 private def GeneratedTypeBuilder moduleToDataType(Module module) {
371 checkArgument(module !== null, "Module reference cannot be NULL.");
373 val moduleDataTypeBuilder = moduleTypeBuilder(module, "Data");
374 addImplementedInterfaceFromUses(module, moduleDataTypeBuilder);
375 moduleDataTypeBuilder.addImplementsType(DATA_ROOT);
376 return moduleDataTypeBuilder;
380 * Converts all <b>rpcs</b> inputs and outputs substatements of the module
\r
381 * to the list of <code>Type</code> objects. In addition are to containers
\r
382 * and lists which belong to input or output also part of returning list.
\r
385 * module from which is obtained set of all rpc objects to
\r
386 * iterate over them
\r
387 * @throws IllegalArgumentException
\r
389 * <li>if the module equals null</li>
\r
390 * <li>if the name of module equals null</li>
\r
391 * <li>if the set of child nodes equals null</li>
\r
395 private def void rpcMethodsToGenType(Module module) {
396 checkArgument(module !== null, "Module reference cannot be NULL.");
397 checkArgument(module.name !== null, "Module name cannot be NULL.");
398 checkArgument(module.childNodes !== null,
399 "Reference to Set of RPC Method Definitions in module " + module.name + " cannot be NULL.");
401 val basePackageName = moduleNamespaceToPackageName(module);
402 val Set<RpcDefinition> rpcDefinitions = module.rpcs;
403 if (rpcDefinitions.isEmpty()) {
407 val interfaceBuilder = moduleTypeBuilder(module, "Service");
408 interfaceBuilder.addImplementsType(Types.typeForClass(RpcService));
409 for (rpc : rpcDefinitions) {
411 val rpcName = parseToClassName(rpc.QName.localName);
412 val rpcMethodName = parseToValidParamName(rpcName);
413 val method = interfaceBuilder.addMethod(rpcMethodName);
414 val input = rpc.input;
415 val output = rpc.output;
417 if (input !== null) {
418 val inType = addRawInterfaceDefinition(basePackageName, input, rpcName);
419 addImplementedInterfaceFromUses(input, inType);
420 inType.addImplementsType(DATA_OBJECT);
421 inType.addImplementsType(augmentable(inType));
422 resolveDataSchemaNodes(module, basePackageName, inType, inType, input.childNodes);
423 genCtx.get(module).addChildNodeType(input.path, inType)
424 val inTypeInstance = inType.toInstance();
425 method.addParameter(inTypeInstance, "input");
428 var Type outTypeInstance = VOID;
429 if (output !== null) {
430 val outType = addRawInterfaceDefinition(basePackageName, output, rpcName);
431 addImplementedInterfaceFromUses(output, outType);
432 outType.addImplementsType(DATA_OBJECT);
433 outType.addImplementsType(augmentable(outType));
434 resolveDataSchemaNodes(module, basePackageName, outType, outType, output.childNodes);
435 genCtx.get(module).addChildNodeType(output.path, outType)
436 outTypeInstance = outType.toInstance();
439 val rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult), outTypeInstance);
440 method.setReturnType(Types.parameterizedTypeFor(FUTURE, rpcRes));
444 genCtx.get(module).addTopLevelNodeType(interfaceBuilder)
448 * Converts all <b>notifications</b> of the module to the list of
\r
449 * <code>Type</code> objects. In addition are to this list added containers
\r
450 * and lists which are part of this notification.
\r
453 * module from which is obtained set of all notification objects
\r
454 * to iterate over them
\r
455 * @throws IllegalArgumentException
\r
457 * <li>if the module equals null</li>
\r
458 * <li>if the name of module equals null</li>
\r
459 * <li>if the set of child nodes equals null</li>
\r
463 private def void notificationsToGenType(Module module) {
464 checkArgument(module !== null, "Module reference cannot be NULL.");
465 checkArgument(module.name !== null, "Module name cannot be NULL.");
467 if (module.childNodes === null) {
468 throw new IllegalArgumentException(
469 "Reference to Set of Notification Definitions in module " + module.name + " cannot be NULL.");
471 val notifications = module.notifications;
472 if(notifications.empty) return;
474 val listenerInterface = moduleTypeBuilder(module, "Listener");
475 listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER);
476 val basePackageName = moduleNamespaceToPackageName(module);
478 for (notification : notifications) {
479 if (notification !== null) {
480 processUsesAugments(notification, module);
482 val notificationInterface = addDefaultInterfaceDefinition(basePackageName, notification,
483 BindingTypes.DATA_OBJECT);
484 notificationInterface.addImplementsType(NOTIFICATION);
485 genCtx.get(module).addChildNodeType(notification.path, notificationInterface)
487 // Notification object
\r
488 resolveDataSchemaNodes(module, basePackageName, notificationInterface, notificationInterface,
489 notification.childNodes);
491 listenerInterface.addMethod("on" + notificationInterface.name) //
\r
492 .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification").
493 setReturnType(Types.VOID);
497 genCtx.get(module).addTopLevelNodeType(listenerInterface)
501 * Converts all <b>identities</b> of the module to the list of
\r
502 * <code>Type</code> objects.
\r
505 * module from which is obtained set of all identity objects to
\r
506 * iterate over them
\r
508 * schema context only used as input parameter for method
\r
509 * {@link identityToGenType}
\r
512 private def void allIdentitiesToGenTypes(Module module, SchemaContext context) {
513 val Set<IdentitySchemaNode> schemaIdentities = module.identities;
514 val basePackageName = moduleNamespaceToPackageName(module);
516 if (schemaIdentities !== null && !schemaIdentities.isEmpty()) {
517 for (identity : schemaIdentities) {
518 identityToGenType(module, basePackageName, identity, context);
524 * Converts the <b>identity</b> object to GeneratedType. Firstly it is
\r
525 * created transport object builder. If identity contains base identity then
\r
526 * reference to base identity is added to superior identity as its extend.
\r
527 * If identity doesn't contain base identity then only reference to abstract
\r
528 * class {@link org.opendaylight.yangtools.yang.model.api.BaseIdentity
\r
529 * BaseIdentity} is added
\r
531 * @param module current module
\r
532 * @param basePackageName
\r
533 * string contains the module package name
\r
535 * IdentitySchemaNode which contains data about identity
\r
537 * SchemaContext which is used to get package and name
\r
538 * information about base of identity
\r
541 private def void identityToGenType(Module module, String basePackageName, IdentitySchemaNode identity,
542 SchemaContext context) {
543 if (identity === null) {
546 val packageName = packageNameForGeneratedType(basePackageName, identity.path);
547 val genTypeName = parseToClassName(identity.QName.localName);
548 val newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
549 val baseIdentity = identity.baseIdentity;
550 if (baseIdentity === null) {
551 newType.setExtendsType(Types.baseIdentityTO);
553 val baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
554 val returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule);
555 val returnTypeName = parseToClassName(baseIdentity.QName.localName);
556 val gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName).toInstance();
557 newType.setExtendsType(gto);
559 newType.setAbstract(true);
560 genCtx.get(module).addIdentityType(newType)
564 * Converts all <b>groupings</b> of the module to the list of
\r
565 * <code>Type</code> objects. Firstly are groupings sorted according mutual
\r
566 * dependencies. At least dependend (indepedent) groupings are in the list
\r
567 * saved at first positions. For every grouping the record is added to map
\r
568 * {@link BindingGeneratorImpl#allGroupings allGroupings}
\r
572 * @param collection of groupings from which types will be generated
\r
575 private def void groupingsToGenTypes(Module module, Collection<GroupingDefinition> groupings) {
576 val basePackageName = moduleNamespaceToPackageName(module);
577 val List<GroupingDefinition> groupingsSortedByDependencies = new GroupingDefinitionDependencySort().sort(
579 for (grouping : groupingsSortedByDependencies) {
580 groupingToGenType(basePackageName, grouping, module);
585 * Converts individual grouping to GeneratedType. Firstly generated type
\r
586 * builder is created and every child node of grouping is resolved to the
\r
589 * @param basePackageName
\r
590 * string contains the module package name
\r
592 * GroupingDefinition which contains data about grouping
\r
593 * @param module current module
\r
594 * @return GeneratedType which is generated from grouping (object of type
\r
595 * <code>GroupingDefinition</code>)
\r
597 private def void groupingToGenType(String basePackageName, GroupingDefinition grouping, Module module) {
598 val packageName = packageNameForGeneratedType(basePackageName, grouping.path);
599 val genType = addDefaultInterfaceDefinition(packageName, grouping);
600 genCtx.get(module).addGroupingType(grouping.path, genType)
601 resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.childNodes);
602 groupingsToGenTypes(module, grouping.groupings);
603 processUsesAugments(grouping, module);
607 * Tries to find EnumTypeDefinition in <code>typeDefinition</code>. If base
\r
608 * type of <code>typeDefinition</code> is of the type ExtendedType then this
\r
609 * method is recursivelly called with this base type.
\r
611 * @param typeDefinition
\r
612 * TypeDefinition in which should be EnumTypeDefinition found as
\r
614 * @return EnumTypeDefinition if it is found inside
\r
615 * <code>typeDefinition</code> or <code>null</code> in other case
\r
617 private def EnumTypeDefinition enumTypeDefFromExtendedType(TypeDefinition<?> typeDefinition) {
618 if (typeDefinition !== null) {
619 if (typeDefinition.baseType instanceof EnumTypeDefinition) {
620 return typeDefinition.baseType as EnumTypeDefinition;
621 } else if (typeDefinition.baseType instanceof ExtendedType) {
622 return enumTypeDefFromExtendedType(typeDefinition.baseType);
629 * Adds enumeration builder created from <code>enumTypeDef</code> to
\r
630 * <code>typeBuilder</code>.
\r
632 * Each <code>enumTypeDef</code> item is added to builder with its name and
\r
635 * @param enumTypeDef
\r
636 * EnumTypeDefinition contains enum data
\r
638 * string contains name which will be assigned to enumeration
\r
640 * @param typeBuilder
\r
641 * GeneratedTypeBuilder to which will be enum builder assigned
\r
642 * @return enumeration builder which contais data from
\r
643 * <code>enumTypeDef</code>
\r
645 private def EnumBuilder resolveInnerEnumFromTypeDefinition(EnumTypeDefinition enumTypeDef, String enumName,
646 GeneratedTypeBuilder typeBuilder) {
647 if ((enumTypeDef !== null) && (typeBuilder !== null) && (enumTypeDef.QName !== null) &&
648 (enumTypeDef.QName.localName !== null)) {
649 val enumerationName = parseToClassName(enumName);
650 val enumBuilder = typeBuilder.addEnumeration(enumerationName);
651 enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
658 * Generates type builder for <code>module</code>.
\r
661 * Module which is source of package name for generated type
\r
664 * string which is added to the module class name representation
\r
666 * @return instance of GeneratedTypeBuilder which represents
\r
667 * <code>module</code>.
\r
668 * @throws IllegalArgumentException
\r
669 * if <code>module</code> equals null
\r
671 private def GeneratedTypeBuilder moduleTypeBuilder(Module module, String postfix) {
672 checkArgument(module !== null, "Module reference cannot be NULL.");
673 val packageName = moduleNamespaceToPackageName(module);
674 val moduleName = parseToClassName(module.name) + postfix;
675 return new GeneratedTypeBuilderImpl(packageName, moduleName);
679 * Converts <code>augSchema</code> to list of <code>Type</code> which
\r
680 * contains generated type for augmentation. In addition there are also
\r
681 * generated types for all containers, list and choices which are child of
\r
682 * <code>augSchema</code> node or a generated types for cases are added if
\r
683 * augmented node is choice.
\r
685 * @param augmentPackageName
\r
686 * string with the name of the package to which the augmentation
\r
689 * AugmentationSchema which is contains data about agumentation
\r
690 * (target path, childs...)
\r
691 * @param module current module
\r
692 * @param parentUsesNode parent uses node of this augment (can be null if this augment is not defined under uses statement)
\r
693 * @throws IllegalArgumentException
\r
695 * <li>if <code>augmentPackageName</code> equals null</li>
\r
696 * <li>if <code>augSchema</code> equals null</li>
\r
697 * <li>if target path of <code>augSchema</code> equals null</li>
\r
700 private def void augmentationToGenTypes(String augmentPackageName, AugmentationSchema augSchema, Module module,
701 UsesNode parentUsesNode) {
702 checkArgument(augmentPackageName !== null, "Package Name cannot be NULL.");
703 checkArgument(augSchema !== null, "Augmentation Schema cannot be NULL.");
704 checkState(augSchema.targetPath !== null,
705 "Augmentation Schema does not contain Target Path (Target Path is NULL).");
707 processUsesAugments(augSchema, module);
709 // EVERY augmented interface will extends Augmentation<T> interface
\r
710 // and DataObject interface
\r
711 val targetPath = augSchema.targetPath;
712 var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
713 if (targetSchemaNode instanceof DataSchemaNode && (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
714 if (parentUsesNode == null) {
715 targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
717 targetSchemaNode = findOriginalTargetFromGrouping(targetSchemaNode.QName.localName, parentUsesNode);
719 if (targetSchemaNode == null) {
720 throw new NullPointerException(
721 "Failed to find target node from grouping for augmentation " + augSchema + " in module " +
726 if (targetSchemaNode !== null) {
727 var targetTypeBuilder = findChildNodeByPath(targetSchemaNode.path)
728 if (targetTypeBuilder === null) {
729 targetTypeBuilder = findCaseByPath(targetSchemaNode.path)
731 if (targetTypeBuilder === null) {
732 throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
734 if (!(targetSchemaNode instanceof ChoiceNode)) {
735 var packageName = augmentPackageName;
736 if (parentUsesNode != null) {
737 packageName = packageNameForGeneratedType(augmentPackageName, augSchema.targetPath);
739 val augTypeBuilder = addRawAugmentGenTypeDefinition(module, packageName, augmentPackageName,
740 targetTypeBuilder.toInstance, augSchema);
741 genCtx.get(module).addAugmentType(augTypeBuilder)
743 generateTypesFromAugmentedChoiceCases(module, augmentPackageName, targetTypeBuilder.toInstance,
744 targetSchemaNode as ChoiceNode, augSchema.childNodes);
750 * Utility method which search for original node defined in grouping.
\r
752 private def DataSchemaNode findOriginal(DataSchemaNode node) {
753 var DataSchemaNode result = findCorrectTargetFromGrouping(node);
754 if (result == null) {
755 result = findCorrectTargetFromAugment(node);
756 if (result != null) {
757 if (result.addedByUses) {
758 result = findOriginal(result);
765 private def DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node) {
766 if (!node.augmenting) {
770 var String currentName = node.QName.localName;
771 var tmpPath = new ArrayList<String>();
772 var YangNode parent = node;
773 var AugmentationSchema augment = null;
775 parent = (parent as DataSchemaNode).parent;
776 if (parent instanceof AugmentationTarget) {
777 tmpPath.add(currentName);
778 augment = findNodeInAugment((parent as AugmentationTarget).availableAugmentations, currentName);
779 if (augment == null) {
780 currentName = (parent as DataSchemaNode).QName.localName;
783 } while ((parent as DataSchemaNode).augmenting && augment == null);
785 if (augment == null) {
788 Collections.reverse(tmpPath);
789 var Object actualParent = augment;
790 var DataSchemaNode result = null;
791 for (name : tmpPath) {
792 if (actualParent instanceof DataNodeContainer) {
793 result = (actualParent as DataNodeContainer).getDataChildByName(name);
794 actualParent = (actualParent as DataNodeContainer).getDataChildByName(name);
796 if (actualParent instanceof ChoiceNode) {
797 result = (actualParent as ChoiceNode).getCaseNodeByName(name);
798 actualParent = (actualParent as ChoiceNode).getCaseNodeByName(name);
803 if (result.addedByUses) {
804 result = findCorrectTargetFromGrouping(result);
811 private def AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, String name) {
812 for (augment : augments) {
813 if (augment.getDataChildByName(name) != null) {
820 private def DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node) {
821 if (node.path.path.size == 1) {
823 // uses is under module statement
\r
824 val Module m = findParentModule(schemaContext, node);
825 var DataSchemaNode result = null;
827 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
828 if (!(targetGrouping instanceof GroupingDefinition)) {
829 throw new IllegalArgumentException("Failed to generate code for augment in " + u);
831 var gr = targetGrouping as GroupingDefinition;
832 result = gr.getDataChildByName(node.QName.localName);
834 if (result == null) {
835 throw new IllegalArgumentException("Failed to generate code for augment");
839 var DataSchemaNode result = null;
840 var String currentName = node.QName.localName;
841 var tmpPath = new ArrayList<String>();
842 var YangNode parent = node.parent;
844 tmpPath.add(currentName);
845 val dataNodeParent = parent as DataNodeContainer;
846 for (u : dataNodeParent.uses) {
847 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
848 if (!(targetGrouping instanceof GroupingDefinition)) {
849 throw new IllegalArgumentException("Failed to generate code for augment in " + u);
851 var gr = targetGrouping as GroupingDefinition;
852 result = gr.getDataChildByName(currentName);
854 if (result == null) {
855 currentName = (parent as SchemaNode).QName.localName;
856 if (parent instanceof DataSchemaNode) {
857 parent = (parent as DataSchemaNode).parent;
859 parent = (parent as DataNodeContainer).parent;
862 } while (result == null && !(parent instanceof Module));
864 if (result != null) {
865 if (tmpPath.size == 1) {
868 var DataSchemaNode newParent = result;
869 Collections.reverse(tmpPath);
871 for (name : tmpPath) {
872 newParent = (newParent as DataNodeContainer).getDataChildByName(name);
883 * Convenient method to find node added by uses statement.
\r
885 private def DataSchemaNode findOriginalTargetFromGrouping(String targetSchemaNodeName, UsesNode parentUsesNode) {
886 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, parentUsesNode.groupingPath.path);
887 if (!(targetGrouping instanceof GroupingDefinition)) {
888 throw new IllegalArgumentException("Failed to generate code for augment in " + parentUsesNode);
891 var grouping = targetGrouping as GroupingDefinition;
892 var result = grouping.getDataChildByName(targetSchemaNodeName);
893 if (result == null) {
896 var boolean fromUses = result.addedByUses;
898 var Iterator<UsesNode> groupingUses = grouping.uses.iterator;
900 if (groupingUses.hasNext()) {
901 grouping = findNodeInSchemaContext(schemaContext, groupingUses.next().groupingPath.path) as GroupingDefinition;
902 result = grouping.getDataChildByName(targetSchemaNodeName);
903 fromUses = result.addedByUses;
905 throw new NullPointerException("Failed to generate code for augment in " + parentUsesNode);
913 * Returns a generated type builder for an augmentation.
\r
915 * The name of the type builder is equal to the name of augmented node with
\r
916 * serial number as suffix.
\r
918 * @param module current module
\r
919 * @param augmentPackageName
\r
920 * string with contains the package name to which the augment
\r
922 * @param basePackageName
\r
923 * string with the package name to which the augmented node
\r
925 * @param targetTypeRef
\r
928 * augmentation schema which contains data about the child nodes
\r
929 * and uses of augment
\r
930 * @return generated type builder for augment
\r
932 private def GeneratedTypeBuilder addRawAugmentGenTypeDefinition(Module module, String augmentPackageName,
933 String basePackageName, Type targetTypeRef, AugmentationSchema augSchema) {
934 var Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
935 if (augmentBuilders === null) {
936 augmentBuilders = new HashMap();
937 genTypeBuilders.put(augmentPackageName, augmentBuilders);
939 val augIdentifier = getAugmentIdentifier(augSchema.unknownSchemaNodes);
941 val augTypeName = if (augIdentifier !== null) {
942 parseToClassName(augIdentifier)
944 augGenTypeName(augmentBuilders, targetTypeRef.name);
947 val augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
949 augTypeBuilder.addImplementsType(DATA_OBJECT);
950 augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
951 addImplementedInterfaceFromUses(augSchema, augTypeBuilder);
953 augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema.childNodes);
954 augmentBuilders.put(augTypeName, augTypeBuilder);
955 return augTypeBuilder;
960 * @param unknownSchemaNodes
\r
961 * @return nodeParameter of UnknownSchemaNode
\r
963 private def String getAugmentIdentifier(List<UnknownSchemaNode> unknownSchemaNodes) {
964 for (unknownSchemaNode : unknownSchemaNodes) {
965 val nodeType = unknownSchemaNode.nodeType;
966 if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.localName) &&
967 YANG_EXT_NAMESPACE.equals(nodeType.namespace.toString())) {
968 return unknownSchemaNode.nodeParameter;
975 * Returns first unique name for the augment generated type builder. The
\r
976 * generated type builder name for augment consists from name of augmented
\r
977 * node and serial number of its augmentation.
\r
980 * map of builders which were created in the package to which the
\r
981 * augmentation belongs
\r
982 * @param genTypeName
\r
983 * string with name of augmented node
\r
984 * @return string with unique name for augmentation builder
\r
986 private def String augGenTypeName(Map<String, GeneratedTypeBuilder> builders, String genTypeName) {
988 while ((builders !== null) && builders.containsKey(genTypeName + index)) {
991 return genTypeName + index;
995 * Adds the methods to <code>typeBuilder</code> which represent subnodes of
\r
996 * node for which <code>typeBuilder</code> was created.
\r
998 * The subnodes aren't mapped to the methods if they are part of grouping or
\r
999 * augment (in this case are already part of them).
\r
1001 * @param module current module
\r
1002 * @param basePackageName
\r
1003 * string contains the module package name
\r
1005 * generated type builder which represents any node. The subnodes
\r
1006 * of this node are added to the <code>typeBuilder</code> as
\r
1007 * methods. The subnode can be of type leaf, leaf-list, list,
\r
1008 * container, choice.
\r
1009 * @param childOf parent type
\r
1010 * @param schemaNodes
\r
1011 * set of data schema nodes which are the children of the node
\r
1012 * for which <code>typeBuilder</code> was created
\r
1013 * @return generated type builder which is the same builder as input
\r
1014 * parameter. The getter methods (representing child nodes) could be
\r
1017 private def GeneratedTypeBuilder resolveDataSchemaNodes(Module module, String basePackageName,
1018 GeneratedTypeBuilder parent, GeneratedTypeBuilder childOf, Set<DataSchemaNode> schemaNodes) {
1019 if ((schemaNodes !== null) && (parent !== null)) {
1020 for (schemaNode : schemaNodes) {
1021 if (!schemaNode.augmenting && !schemaNode.addedByUses) {
1022 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module);
1030 * Adds the methods to <code>typeBuilder</code> what represents subnodes of
\r
1031 * node for which <code>typeBuilder</code> was created.
\r
1033 * @param module current module
\r
1034 * @param basePackageName
\r
1035 * string contains the module package name
\r
1036 * @param typeBuilder
\r
1037 * generated type builder which represents any node. The subnodes
\r
1038 * of this node are added to the <code>typeBuilder</code> as
\r
1039 * methods. The subnode can be of type leaf, leaf-list, list,
\r
1040 * container, choice.
\r
1041 * @param childOf parent type
\r
1042 * @param schemaNodes
\r
1043 * set of data schema nodes which are the children of the node
\r
1044 * for which <code>typeBuilder</code> was created
\r
1045 * @return generated type builder which is the same object as the input
\r
1046 * parameter <code>typeBuilder</code>. The getter method could be
\r
1049 private def GeneratedTypeBuilder augSchemaNodeToMethods(Module module, String basePackageName,
1050 GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Set<DataSchemaNode> schemaNodes) {
1051 if ((schemaNodes !== null) && (typeBuilder !== null)) {
1052 for (schemaNode : schemaNodes) {
1053 if (!schemaNode.isAugmenting()) {
1054 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module);
1062 * Adds to <code>typeBuilder</code> a method which is derived from
\r
1063 * <code>schemaNode</code>.
\r
1065 * @param basePackageName
\r
1066 * string with the module package name
\r
1068 * data schema node which is added to <code>typeBuilder</code> as
\r
1070 * @param typeBuilder
\r
1071 * generated type builder to which is <code>schemaNode</code>
\r
1072 * added as a method.
\r
1073 * @param childOf parent type
\r
1074 * @param module current module
\r
1076 private def void addSchemaNodeToBuilderAsMethod(String basePackageName, DataSchemaNode node,
1077 GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Module module) {
1078 if (node !== null && typeBuilder !== null) {
1080 case node instanceof LeafSchemaNode:
1081 resolveLeafSchemaNodeAsMethod(typeBuilder, node as LeafSchemaNode)
1082 case node instanceof LeafListSchemaNode:
1083 resolveLeafListSchemaNode(typeBuilder, node as LeafListSchemaNode)
1084 case node instanceof ContainerSchemaNode:
1085 containerToGenType(module, basePackageName, typeBuilder, childOf, node as ContainerSchemaNode)
1086 case node instanceof ListSchemaNode:
1087 listToGenType(module, basePackageName, typeBuilder, childOf, node as ListSchemaNode)
1088 case node instanceof ChoiceNode:
1089 choiceToGeneratedType(module, basePackageName, typeBuilder, node as ChoiceNode)
1095 * Converts <code>choiceNode</code> to the list of generated types for
\r
1096 * choice and its cases.
\r
1098 * The package names for choice and for its cases are created as
\r
1099 * concatenation of the module package (<code>basePackageName</code>) and
\r
1100 * names of all parents node.
\r
1102 * @param module current module
\r
1103 * @param basePackageName
\r
1104 * string with the module package name
\r
1105 * @param parent parent type
\r
1106 * @param childOf concrete parent for case child nodes
\r
1107 * @param choiceNode
\r
1108 * choice node which is mapped to generated type. Also child
\r
1109 * nodes - cases are mapped to generated types.
\r
1110 * @throws IllegalArgumentException
\r
1112 * <li>if <code>basePackageName</code> equals null</li>
\r
1113 * <li>if <code>choiceNode</code> equals null</li>
\r
1117 private def void choiceToGeneratedType(Module module, String basePackageName, GeneratedTypeBuilder parent,
1118 ChoiceNode choiceNode) {
1119 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1120 checkArgument(choiceNode !== null, "Choice Schema Node cannot be NULL.");
1122 val packageName = packageNameForGeneratedType(basePackageName, choiceNode.path);
1123 val choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
1124 constructGetter(parent, choiceNode.QName.localName, choiceNode.description, choiceTypeBuilder);
1125 choiceTypeBuilder.addImplementsType(DataContainer.typeForClass);
1126 genCtx.get(module).addChildNodeType(choiceNode.path, choiceTypeBuilder)
1127 generateTypesFromChoiceCases(module, basePackageName, parent, choiceTypeBuilder.toInstance, choiceNode);
1131 * Converts <code>caseNodes</code> set to list of corresponding generated
\r
1134 * For every <i>case</i> which isn't added through augment or <i>uses</i> is
\r
1135 * created generated type builder. The package names for the builder is
\r
1136 * created as concatenation of the module package (
\r
1137 * <code>basePackageName</code>) and names of all parents nodes of the
\r
1138 * concrete <i>case</i>. There is also relation "<i>implements type</i>"
\r
1139 * between every case builder and <i>choice</i> type
\r
1141 * @param basePackageName
\r
1142 * string with the module package name
\r
1143 * @param refChoiceType
\r
1144 * type which represents superior <i>case</i>
\r
1145 * @param caseNodes
\r
1146 * set of choice case nodes which are mapped to generated types
\r
1147 * @return list of generated types for <code>caseNodes</code>.
\r
1148 * @throws IllegalArgumentException
\r
1150 * <li>if <code>basePackageName</code> equals null</li>
\r
1151 * <li>if <code>refChoiceType</code> equals null</li>
\r
1152 * <li>if <code>caseNodes</code> equals null</li>
\r
1156 private def void generateTypesFromChoiceCases(Module module, String basePackageName,
1157 GeneratedTypeBuilder choiceParent, Type refChoiceType, ChoiceNode choiceNode) {
1158 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1159 checkArgument(refChoiceType !== null, "Referenced Choice Type cannot be NULL.");
1160 checkArgument(choiceNode !== null, "ChoiceNode cannot be NULL.");
1162 val Set<ChoiceCaseNode> caseNodes = choiceNode.cases;
1163 if (caseNodes == null) {
1167 for (caseNode : caseNodes) {
1168 if (caseNode !== null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
1169 val packageName = packageNameForGeneratedType(basePackageName, caseNode.path);
1170 val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
1171 caseTypeBuilder.addImplementsType(refChoiceType);
1172 genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder)
1173 val Set<DataSchemaNode> caseChildNodes = caseNode.childNodes;
1174 if (caseChildNodes !== null) {
1175 val parentNode = choiceNode.parent;
1176 var SchemaNode parent;
1177 if (parentNode instanceof AugmentationSchema) {
1178 val augSchema = parentNode as AugmentationSchema;
1179 val targetPath = augSchema.targetPath;
1180 var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
1181 if (targetSchemaNode instanceof DataSchemaNode &&
1182 (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
1183 targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
1184 if (targetSchemaNode == null) {
1185 throw new NullPointerException(
1186 "Failed to find target node from grouping for augmentation " + augSchema +
1187 " in module " + module.name);
1190 parent = targetSchemaNode as SchemaNode
1192 parent = choiceNode.parent as SchemaNode;
1194 var GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.path)
1195 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes);
1199 processUsesAugments(caseNode, module);
1204 * Generates list of generated types for all the cases of a choice which are
\r
1205 * added to the choice through the augment.
\r
1208 * @param basePackageName
\r
1209 * string contains name of package to which augment belongs. If
\r
1210 * an augmented choice is from an other package (pcg1) than an
\r
1211 * augmenting choice (pcg2) then case's of the augmenting choice
\r
1212 * will belong to pcg2.
\r
1213 * @param refChoiceType
\r
1214 * Type which represents the choice to which case belongs. Every
\r
1215 * case has to contain its choice in extend part.
\r
1216 * @param caseNodes
\r
1217 * set of choice case nodes for which is checked if are/aren't
\r
1218 * added to choice through augmentation
\r
1219 * @return list of generated types which represents augmented cases of
\r
1220 * choice <code>refChoiceType</code>
\r
1221 * @throws IllegalArgumentException
\r
1223 * <li>if <code>basePackageName</code> equals null</li>
\r
1224 * <li>if <code>refChoiceType</code> equals null</li>
\r
1225 * <li>if <code>caseNodes</code> equals null</li>
\r
1228 private def void generateTypesFromAugmentedChoiceCases(Module module, String basePackageName, Type targetType,
1229 ChoiceNode targetNode, Set<DataSchemaNode> augmentedNodes) {
1230 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1231 checkArgument(targetType !== null, "Referenced Choice Type cannot be NULL.");
1232 checkArgument(augmentedNodes !== null, "Set of Choice Case Nodes cannot be NULL.");
1234 for (caseNode : augmentedNodes) {
1235 if (caseNode !== null) {
1236 val packageName = packageNameForGeneratedType(basePackageName, caseNode.path);
1237 val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
1238 caseTypeBuilder.addImplementsType(targetType);
1240 val SchemaNode parent = targetNode.parent as SchemaNode;
1241 var GeneratedTypeBuilder childOfType = null;
1242 if (parent instanceof Module) {
1243 childOfType = genCtx.get(parent as Module).moduleNode
1244 } else if (parent instanceof ChoiceCaseNode) {
1245 childOfType = findCaseByPath(parent.path)
1246 } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) {
1247 childOfType = findChildNodeByPath(parent.path)
1248 } else if (parent instanceof GroupingDefinition) {
1249 childOfType = findGroupingByPath(parent.path);
1252 if (childOfType == null) {
1253 throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode);
1256 if (caseNode instanceof DataNodeContainer) {
1257 val DataNodeContainer dataNodeCase = caseNode as DataNodeContainer;
1258 val Set<DataSchemaNode> childNodes = dataNodeCase.childNodes;
1259 if (childNodes !== null) {
1260 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
1263 val ChoiceCaseNode node = targetNode.getCaseNodeByName(caseNode.getQName().getLocalName());
1264 val Set<DataSchemaNode> childNodes = node.childNodes;
1265 if (childNodes !== null) {
1266 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
1270 genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder)
1277 * Converts <code>leaf</code> to the getter method which is added to
\r
1278 * <code>typeBuilder</code>.
\r
1280 * @param typeBuilder
\r
1281 * generated type builder to which is added getter method as
\r
1282 * <code>leaf</code> mapping
\r
1284 * leaf schema node which is mapped as getter method which is
\r
1285 * added to <code>typeBuilder</code>
\r
1286 * @return boolean value
\r
1288 * <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
\r
1290 * <li>true - in other cases</li>
\r
1293 private def boolean resolveLeafSchemaNodeAsMethod(GeneratedTypeBuilder typeBuilder, LeafSchemaNode leaf) {
1294 if ((leaf !== null) && (typeBuilder !== null)) {
1295 val leafName = leaf.QName.localName;
1296 var String leafDesc = leaf.description;
1297 if (leafDesc === null) {
1301 val parentModule = findParentModule(schemaContext, leaf);
1302 if (leafName !== null && !leaf.isAddedByUses()) {
1303 val TypeDefinition<?> typeDef = leaf.type;
1305 var Type returnType = null;
1306 if (typeDef instanceof EnumTypeDefinition) {
1307 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
1308 val enumTypeDef = typeDef as EnumTypeDefinition;
1309 val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leafName, typeBuilder);
1311 if (enumBuilder !== null) {
1312 returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name);
1314 (typeProvider as TypeProviderImpl).putReferencedType(leaf.path, returnType);
1315 } else if (typeDef instanceof UnionType) {
1316 val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
1317 if (genTOBuilder !== null) {
1318 returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
1320 } else if (typeDef instanceof BitsTypeDefinition) {
1321 val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
1322 if (genTOBuilder !== null) {
1323 returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
1326 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
1328 if (returnType !== null) {
1329 val MethodSignatureBuilder getter = constructGetter(typeBuilder, leafName, leafDesc, returnType);
1330 processContextRefExtension(leaf, getter, parentModule);
1338 private def void processContextRefExtension(LeafSchemaNode leaf, MethodSignatureBuilder getter, Module module) {
1339 for (node : leaf.unknownSchemaNodes) {
1340 val nodeType = node.nodeType;
1341 if ("context-reference".equals(nodeType.localName)) {
1342 val nodeParam = node.nodeParameter;
1343 var IdentitySchemaNode identity = null;
1344 var String basePackageName = null;
1345 val String[] splittedElement = nodeParam.split(":");
1346 if (splittedElement.length == 1) {
1347 identity = findIdentityByName(module.identities, splittedElement.get(0));
1348 basePackageName = moduleNamespaceToPackageName(module);
1349 } else if (splittedElement.length == 2) {
1350 var prefix = splittedElement.get(0);
1351 val Module dependentModule = findModuleFromImports(module.imports, prefix)
1352 if (dependentModule == null) {
1353 throw new IllegalArgumentException(
1354 "Failed to process context-reference: unknown prefix " + prefix);
1356 identity = findIdentityByName(dependentModule.identities, splittedElement.get(1));
1357 basePackageName = moduleNamespaceToPackageName(dependentModule);
1359 throw new IllegalArgumentException(
1360 "Failed to process context-reference: unknown identity " + nodeParam);
1362 if (identity == null) {
1363 throw new IllegalArgumentException(
1364 "Failed to process context-reference: unknown identity " + nodeParam);
1367 val Class<RoutingContext> clazz = typeof(RoutingContext);
1368 val AnnotationTypeBuilder rc = getter.addAnnotation(clazz.package.name, clazz.simpleName);
1369 val packageName = packageNameForGeneratedType(basePackageName, identity.path);
1370 val genTypeName = parseToClassName(identity.QName.localName);
1371 rc.addParameter("value", packageName + "." + genTypeName + ".class");
1376 private def IdentitySchemaNode findIdentityByName(Set<IdentitySchemaNode> identities, String name) {
1377 for (id : identities) {
1378 if (id.QName.localName.equals(name)) {
1385 private def Module findModuleFromImports(Set<ModuleImport> imports, String prefix) {
1386 for (imp : imports) {
1387 if (imp.prefix.equals(prefix)) {
1388 return schemaContext.findModuleByName(imp.moduleName, imp.revision);
1395 * Converts <code>leaf</code> schema node to property of generated TO
\r
1398 * @param toBuilder
\r
1399 * generated TO builder to which is <code>leaf</code> added as
\r
1402 * leaf schema node which is added to <code>toBuilder</code> as
\r
1404 * @param isReadOnly
\r
1405 * boolean value which says if leaf property is|isn't read only
\r
1406 * @return boolean value
\r
1408 * <li>false - if <code>leaf</code>, <code>toBuilder</code> or leaf
\r
1409 * name equals null or if leaf is added by <i>uses</i>.</li>
\r
1410 * <li>true - other cases</li>
\r
1413 private def boolean resolveLeafSchemaNodeAsProperty(GeneratedTOBuilder toBuilder, LeafSchemaNode leaf,
1414 boolean isReadOnly) {
1415 if ((leaf !== null) && (toBuilder !== null)) {
1416 val leafName = leaf.QName.localName;
1417 var String leafDesc = leaf.description;
1418 if (leafDesc === null) {
1422 if (leafName !== null) {
1423 val TypeDefinition<?> typeDef = leaf.type;
1425 // TODO: properly resolve enum types
\r
1426 val returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
1428 if (returnType !== null) {
1429 val propBuilder = toBuilder.addProperty(parseToClassName(leafName));
1431 propBuilder.setReadOnly(isReadOnly);
1432 propBuilder.setReturnType(returnType);
1433 propBuilder.setComment(leafDesc);
1435 toBuilder.addEqualsIdentity(propBuilder);
1436 toBuilder.addHashIdentity(propBuilder);
1437 toBuilder.addToStringProperty(propBuilder);
1447 * Converts <code>node</code> leaf list schema node to getter method of
\r
1448 * <code>typeBuilder</code>.
\r
1450 * @param typeBuilder
\r
1451 * generated type builder to which is <code>node</code> added as
\r
1454 * leaf list schema node which is added to
\r
1455 * <code>typeBuilder</code> as getter method
\r
1456 * @return boolean value
\r
1458 * <li>true - if <code>node</code>, <code>typeBuilder</code>,
\r
1459 * nodeName equal null or <code>node</code> is added by <i>uses</i></li>
\r
1460 * <li>false - other cases</li>
\r
1463 private def boolean resolveLeafListSchemaNode(GeneratedTypeBuilder typeBuilder, LeafListSchemaNode node) {
1464 if ((node !== null) && (typeBuilder !== null)) {
1465 val nodeName = node.QName.localName;
1466 var String nodeDesc = node.description;
1467 if (nodeDesc === null) {
1470 if (nodeName !== null && !node.isAddedByUses()) {
1471 val TypeDefinition<?> type = node.type;
1472 val listType = Types.listTypeFor(typeProvider.javaTypeForSchemaDefinitionType(type, node));
1473 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
1480 private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode) {
1481 return addDefaultInterfaceDefinition(packageName, schemaNode, null);
1485 * Instantiates generated type builder with <code>packageName</code> and
\r
1486 * <code>schemaNode</code>.
\r
1488 * The new builder always implements
\r
1489 * {@link org.opendaylight.yangtools.yang.binding.DataObject DataObject}.<br />
\r
1490 * If <code>schemaNode</code> is instance of GroupingDefinition it also
\r
1491 * implements {@link org.opendaylight.yangtools.yang.binding.Augmentable
\r
1492 * Augmentable}.<br />
\r
1493 * If <code>schemaNode</code> is instance of
\r
1494 * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
\r
1495 * DataNodeContainer} it can also implement nodes which are specified in
\r
1498 * @param packageName
\r
1499 * string with the name of the package to which
\r
1500 * <code>schemaNode</code> belongs.
\r
1501 * @param schemaNode
\r
1502 * schema node for which is created generated type builder
\r
1503 * @param parent parent type (can be null)
\r
1504 * @return generated type builder <code>schemaNode</code>
\r
1506 private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode,
1508 val builder = addRawInterfaceDefinition(packageName, schemaNode, "");
1509 if (parent === null) {
1510 builder.addImplementsType(DATA_OBJECT);
1512 builder.addImplementsType(BindingTypes.childOf(parent));
1514 if (!(schemaNode instanceof GroupingDefinition)) {
1515 builder.addImplementsType(augmentable(builder));
1518 if (schemaNode instanceof DataNodeContainer) {
1519 addImplementedInterfaceFromUses(schemaNode as DataNodeContainer, builder);
1526 * Wraps the calling of the same overloaded method.
\r
1528 * @param packageName
\r
1529 * string with the package name to which returning generated type
\r
1531 * @param schemaNode
\r
1532 * schema node which provide data about the schema node name
\r
1533 * @return generated type builder for <code>schemaNode</code>
\r
1535 private def GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode) {
1536 return addRawInterfaceDefinition(packageName, schemaNode, "");
1540 * Returns reference to generated type builder for specified
\r
1541 * <code>schemaNode</code> with <code>packageName</code>.
\r
1543 * Firstly the generated type builder is searched in
\r
1544 * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
\r
1545 * found it is created and added to <code>genTypeBuilders</code>.
\r
1547 * @param packageName
\r
1548 * string with the package name to which returning generated type
\r
1550 * @param schemaNode
\r
1551 * schema node which provide data about the schema node name
\r
1552 * @param prefix return type name prefix
\r
1553 * @return generated type builder for <code>schemaNode</code>
\r
1554 * @throws IllegalArgumentException
\r
1556 * <li>if <code>schemaNode</code> equals null</li>
\r
1557 * <li>if <code>packageName</code> equals null</li>
\r
1558 * <li>if Q name of schema node is null</li>
\r
1559 * <li>if schema node name is nul</li>
\r
1563 private def GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode,
1565 checkArgument(schemaNode !== null, "Data Schema Node cannot be NULL.");
1566 checkArgument(packageName !== null, "Package Name for Generated Type cannot be NULL.");
1567 checkArgument(schemaNode.QName !== null, "QName for Data Schema Node cannot be NULL.");
1568 val schemaNodeName = schemaNode.QName.localName;
1569 checkArgument(schemaNodeName !== null, "Local Name of QName for Data Schema Node cannot be NULL.");
1571 var String genTypeName;
1572 if (prefix === null) {
1573 genTypeName = parseToClassName(schemaNodeName);
1575 genTypeName = prefix + parseToClassName(schemaNodeName);
1578 //FIXME: Validation of name conflict
\r
1579 val newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
1580 if (!genTypeBuilders.containsKey(packageName)) {
1581 val Map<String, GeneratedTypeBuilder> builders = new HashMap();
1582 builders.put(genTypeName, newType);
1583 genTypeBuilders.put(packageName, builders);
1585 val Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
1586 if (!builders.containsKey(genTypeName)) {
1587 builders.put(genTypeName, newType);
1594 * Creates the name of the getter method from <code>methodName</code>.
\r
1596 * @param methodName
\r
1597 * string with the name of the getter method
\r
1598 * @param returnType return type
\r
1599 * @return string with the name of the getter method for
\r
1600 * <code>methodName</code> in JAVA method format
\r
1602 private def String getterMethodName(String methodName, Type returnType) {
1603 val method = new StringBuilder();
1604 if (BOOLEAN.equals(returnType)) {
1605 method.append("is");
1607 method.append("get");
1609 method.append(parseToClassName(methodName));
1610 return method.toString();
1614 * Created a method signature builder as part of
\r
1615 * <code>interfaceBuilder</code>.
\r
1617 * The method signature builder is created for the getter method of
\r
1618 * <code>schemaNodeName</code>. Also <code>comment</code> and
\r
1619 * <code>returnType</code> information are added to the builder.
\r
1621 * @param interfaceBuilder
\r
1622 * generated type builder for which the getter method should be
\r
1624 * @param schemaNodeName
\r
1625 * string with schema node name. The name will be the part of the
\r
1626 * getter method name.
\r
1628 * string with comment for the getter method
\r
1629 * @param returnType
\r
1630 * type which represents the return type of the getter method
\r
1631 * @return method signature builder which represents the getter method of
\r
1632 * <code>interfaceBuilder</code>
\r
1634 private def MethodSignatureBuilder constructGetter(GeneratedTypeBuilder interfaceBuilder, String schemaNodeName,
1635 String comment, Type returnType) {
1636 val getMethod = interfaceBuilder.addMethod(getterMethodName(schemaNodeName, returnType));
1637 getMethod.setComment(comment);
1638 getMethod.setReturnType(returnType);
1643 * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
\r
1644 * or to <code>genTOBuilder</code> as property.
\r
1646 * @param basePackageName
\r
1647 * string contains the module package name
\r
1648 * @param schemaNode
\r
1649 * data schema node which should be added as getter method to
\r
1650 * <code>typeBuilder</code> or as a property to
\r
1651 * <code>genTOBuilder</code> if is part of the list key
\r
1652 * @param typeBuilder
\r
1653 * generated type builder for the list schema node
\r
1654 * @param genTOBuilder
\r
1655 * generated TO builder for the list keys
\r
1657 * list of string which contains names of the list keys
\r
1658 * @param module current module
\r
1659 * @throws IllegalArgumentException
\r
1661 * <li>if <code>schemaNode</code> equals null</li>
\r
1662 * <li>if <code>typeBuilder</code> equals null</li>
\r
1665 private def void addSchemaNodeToListBuilders(String basePackageName, DataSchemaNode schemaNode,
1666 GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder, List<String> listKeys, Module module) {
1667 checkArgument(schemaNode !== null, "Data Schema Node cannot be NULL.");
1668 checkArgument(typeBuilder !== null, "Generated Type Builder cannot be NULL.");
1670 if (schemaNode instanceof LeafSchemaNode) {
1671 val leaf = schemaNode as LeafSchemaNode;
1672 val leafName = leaf.QName.localName;
1673 if (!listKeys.contains(leafName)) {
1674 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
1676 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
1678 } else if (!schemaNode.addedByUses) {
1679 if (schemaNode instanceof LeafListSchemaNode) {
1680 resolveLeafListSchemaNode(typeBuilder, schemaNode as LeafListSchemaNode);
1681 } else if (schemaNode instanceof ContainerSchemaNode) {
1682 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, schemaNode as ContainerSchemaNode);
1683 } else if (schemaNode instanceof ChoiceNode) {
1684 choiceToGeneratedType(module, basePackageName, typeBuilder, schemaNode as ChoiceNode);
1685 } else if (schemaNode instanceof ListSchemaNode) {
1686 listToGenType(module, basePackageName, typeBuilder, typeBuilder, schemaNode as ListSchemaNode);
1691 private def typeBuildersToGenTypes(Module module, GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder) {
1692 checkArgument(typeBuilder !== null, "Generated Type Builder cannot be NULL.");
1694 if (genTOBuilder !== null) {
1695 val genTO = genTOBuilder.toInstance();
1696 constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO);
1697 genCtx.get(module).addGeneratedTOBuilder(genTOBuilder)
1702 * Selects the names of the list keys from <code>list</code> and returns
\r
1703 * them as the list of the strings
\r
1706 * of string with names of the list keys
\r
1707 * @return list of string which represents names of the list keys. If the
\r
1708 * <code>list</code> contains no keys then the empty list is
\r
1711 private def listKeys(ListSchemaNode list) {
1712 val List<String> listKeys = new ArrayList();
1714 if (list.keyDefinition !== null) {
1715 val keyDefinitions = list.keyDefinition;
1716 for (keyDefinition : keyDefinitions) {
1717 listKeys.add(keyDefinition.localName);
1724 * Generates for the <code>list</code> which contains any list keys special
\r
1725 * generated TO builder.
\r
1727 * @param packageName
\r
1728 * string with package name to which the list belongs
\r
1730 * list schema node which is source of data about the list name
\r
1731 * @return generated TO builder which represents the keys of the
\r
1732 * <code>list</code> or null if <code>list</code> is null or list of
\r
1733 * key definitions is null or empty.
\r
1735 private def GeneratedTOBuilder resolveListKeyTOBuilder(String packageName, ListSchemaNode list) {
1736 var GeneratedTOBuilder genTOBuilder = null;
1737 if ((list.keyDefinition !== null) && (!list.keyDefinition.isEmpty())) {
1738 if (list !== null) {
1739 val listName = list.QName.localName + "Key";
1740 val String genTOName = parseToClassName(listName);
1741 genTOBuilder = new GeneratedTOBuilderImpl(packageName, genTOName);
1744 return genTOBuilder;
1748 * Builds generated TO builders for <code>typeDef</code> of type
\r
1749 * {@link org.opendaylight.yangtools.yang.model.util.UnionType UnionType} or
\r
1750 * {@link org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
\r
1751 * BitsTypeDefinition} which are also added to <code>typeBuilder</code> as
\r
1752 * enclosing transfer object.
\r
1754 * If more then one generated TO builder is created for enclosing then all
\r
1755 * of the generated TO builders are added to <code>typeBuilder</code> as
\r
1756 * enclosing transfer objects.
\r
1759 * type definition which can be of type <code>UnionType</code> or
\r
1760 * <code>BitsTypeDefinition</code>
\r
1761 * @param typeBuilder
\r
1762 * generated type builder to which is added generated TO created
\r
1763 * from <code>typeDef</code>
\r
1765 * string with name for generated TO builder
\r
1767 * @param parentModule
\r
1768 * @return generated TO builder for <code>typeDef</code>
\r
1770 private def GeneratedTOBuilder addTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
1771 String leafName, LeafSchemaNode leaf, Module parentModule) {
1772 val classNameFromLeaf = parseToClassName(leafName);
1773 val List<GeneratedTOBuilder> genTOBuilders = new ArrayList();
1774 val packageName = typeBuilder.fullyQualifiedName;
1775 if (typeDef instanceof UnionTypeDefinition) {
1776 genTOBuilders.addAll(
1777 (typeProvider as TypeProviderImpl).
1778 provideGeneratedTOBuildersForUnionTypeDef(packageName, (typeDef as UnionTypeDefinition),
1779 classNameFromLeaf, leaf));
1780 } else if (typeDef instanceof BitsTypeDefinition) {
1782 ((typeProvider as TypeProviderImpl) ).
1783 provideGeneratedTOBuilderForBitsTypeDefinition(packageName, typeDef, classNameFromLeaf));
1785 if (genTOBuilders !== null && !genTOBuilders.isEmpty()) {
1786 for (genTOBuilder : genTOBuilders) {
1787 typeBuilder.addEnclosingTransferObject(genTOBuilder);
1789 return genTOBuilders.get(0);
1796 * Adds the implemented types to type builder.
\r
1798 * The method passes through the list of <i>uses</i> in
\r
1799 * {@code dataNodeContainer}. For every <i>use</i> is obtained coresponding
\r
1800 * generated type from {@link BindingGeneratorImpl#allGroupings
\r
1801 * allGroupings} which is added as <i>implements type</i> to
\r
1802 * <code>builder</code>
\r
1804 * @param dataNodeContainer
\r
1805 * element which contains the list of used YANG groupings
\r
1807 * builder to which are added implemented types according to
\r
1808 * <code>dataNodeContainer</code>
\r
1809 * @return generated type builder with all implemented types
\r
1811 private def addImplementedInterfaceFromUses(DataNodeContainer dataNodeContainer, GeneratedTypeBuilder builder) {
1812 for (usesNode : dataNodeContainer.uses) {
1813 if (usesNode.groupingPath !== null) {
1814 val genType = findGroupingByPath(usesNode.groupingPath).toInstance
1815 if (genType === null) {
1816 throw new IllegalStateException(
1817 "Grouping " + usesNode.groupingPath + "is not resolved for " + builder.name);
1819 builder.addImplementsType(genType);
1825 private def GeneratedTypeBuilder findChildNodeByPath(SchemaPath path) {
1826 for (ctx : genCtx.values) {
1827 var result = ctx.getChildNode(path)
1828 if (result !== null) {
1835 private def GeneratedTypeBuilder findGroupingByPath(SchemaPath path) {
1836 for (ctx : genCtx.values) {
1837 var result = ctx.getGrouping(path)
1838 if (result !== null) {
1845 private def GeneratedTypeBuilder findCaseByPath(SchemaPath path) {
1846 for (ctx : genCtx.values) {
1847 var result = ctx.getCase(path)
1848 if (result !== null) {