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 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
850 if (!(targetGrouping instanceof GroupingDefinition)) {
851 throw new IllegalArgumentException("Failed to generate code for augment in " + u);
853 var gr = targetGrouping as GroupingDefinition;
854 result = gr.getDataChildByName(currentName);
856 if (result == null) {
857 currentName = (parent as SchemaNode).QName.localName;
858 if (parent instanceof DataSchemaNode) {
859 parent = (parent as DataSchemaNode).parent;
861 parent = (parent as DataNodeContainer).parent;
864 } while (result == null && !(parent instanceof Module));
866 if (result != null) {
867 if (tmpPath.size == 1) {
870 var DataSchemaNode newParent = result;
871 Collections.reverse(tmpPath);
873 for (name : tmpPath) {
874 newParent = (newParent as DataNodeContainer).getDataChildByName(name);
885 * Convenient method to find node added by uses statement.
\r
887 private def DataSchemaNode findOriginalTargetFromGrouping(String targetSchemaNodeName, UsesNode parentUsesNode) {
888 var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, parentUsesNode.groupingPath.path);
889 if (!(targetGrouping instanceof GroupingDefinition)) {
890 throw new IllegalArgumentException("Failed to generate code for augment in " + parentUsesNode);
893 var grouping = targetGrouping as GroupingDefinition;
894 var result = grouping.getDataChildByName(targetSchemaNodeName);
895 if (result == null) {
898 var boolean fromUses = result.addedByUses;
900 var Iterator<UsesNode> groupingUses = grouping.uses.iterator;
902 if (groupingUses.hasNext()) {
903 grouping = findNodeInSchemaContext(schemaContext, groupingUses.next().groupingPath.path) as GroupingDefinition;
904 result = grouping.getDataChildByName(targetSchemaNodeName);
905 fromUses = result.addedByUses;
907 throw new NullPointerException("Failed to generate code for augment in " + parentUsesNode);
915 * Returns a generated type builder for an augmentation.
\r
917 * The name of the type builder is equal to the name of augmented node with
\r
918 * serial number as suffix.
\r
920 * @param module current module
\r
921 * @param augmentPackageName
\r
922 * string with contains the package name to which the augment
\r
924 * @param basePackageName
\r
925 * string with the package name to which the augmented node
\r
927 * @param targetTypeRef
\r
930 * augmentation schema which contains data about the child nodes
\r
931 * and uses of augment
\r
932 * @return generated type builder for augment
\r
934 private def GeneratedTypeBuilder addRawAugmentGenTypeDefinition(Module module, String augmentPackageName,
935 String basePackageName, Type targetTypeRef, AugmentationSchema augSchema) {
936 var Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
937 if (augmentBuilders === null) {
938 augmentBuilders = new HashMap();
939 genTypeBuilders.put(augmentPackageName, augmentBuilders);
941 val augIdentifier = getAugmentIdentifier(augSchema.unknownSchemaNodes);
943 val augTypeName = if (augIdentifier !== null) {
944 parseToClassName(augIdentifier)
946 augGenTypeName(augmentBuilders, targetTypeRef.name);
949 val augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
951 augTypeBuilder.addImplementsType(DATA_OBJECT);
952 augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
953 addImplementedInterfaceFromUses(augSchema, augTypeBuilder);
955 augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema.childNodes);
956 augmentBuilders.put(augTypeName, augTypeBuilder);
957 return augTypeBuilder;
962 * @param unknownSchemaNodes
\r
963 * @return nodeParameter of UnknownSchemaNode
\r
965 private def String getAugmentIdentifier(List<UnknownSchemaNode> unknownSchemaNodes) {
966 for (unknownSchemaNode : unknownSchemaNodes) {
967 val nodeType = unknownSchemaNode.nodeType;
968 if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.localName) &&
969 YANG_EXT_NAMESPACE.equals(nodeType.namespace.toString())) {
970 return unknownSchemaNode.nodeParameter;
977 * Returns first unique name for the augment generated type builder. The
\r
978 * generated type builder name for augment consists from name of augmented
\r
979 * node and serial number of its augmentation.
\r
982 * map of builders which were created in the package to which the
\r
983 * augmentation belongs
\r
984 * @param genTypeName
\r
985 * string with name of augmented node
\r
986 * @return string with unique name for augmentation builder
\r
988 private def String augGenTypeName(Map<String, GeneratedTypeBuilder> builders, String genTypeName) {
990 while ((builders !== null) && builders.containsKey(genTypeName + index)) {
993 return genTypeName + index;
997 * Adds the methods to <code>typeBuilder</code> which represent subnodes of
\r
998 * node for which <code>typeBuilder</code> was created.
\r
1000 * The subnodes aren't mapped to the methods if they are part of grouping or
\r
1001 * augment (in this case are already part of them).
\r
1003 * @param module current module
\r
1004 * @param basePackageName
\r
1005 * string contains the module package name
\r
1007 * generated type builder which represents any node. The subnodes
\r
1008 * of this node are added to the <code>typeBuilder</code> as
\r
1009 * methods. The subnode can be of type leaf, leaf-list, list,
\r
1010 * container, choice.
\r
1011 * @param childOf parent type
\r
1012 * @param schemaNodes
\r
1013 * set of data schema nodes which are the children of the node
\r
1014 * for which <code>typeBuilder</code> was created
\r
1015 * @return generated type builder which is the same builder as input
\r
1016 * parameter. The getter methods (representing child nodes) could be
\r
1019 private def GeneratedTypeBuilder resolveDataSchemaNodes(Module module, String basePackageName,
1020 GeneratedTypeBuilder parent, GeneratedTypeBuilder childOf, Set<DataSchemaNode> schemaNodes) {
1021 if ((schemaNodes !== null) && (parent !== null)) {
1022 for (schemaNode : schemaNodes) {
1023 if (!schemaNode.augmenting && !schemaNode.addedByUses) {
1024 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module);
1032 * Adds the methods to <code>typeBuilder</code> what represents subnodes of
\r
1033 * node for which <code>typeBuilder</code> was created.
\r
1035 * @param module current module
\r
1036 * @param basePackageName
\r
1037 * string contains the module package name
\r
1038 * @param typeBuilder
\r
1039 * generated type builder which represents any node. The subnodes
\r
1040 * of this node are added to the <code>typeBuilder</code> as
\r
1041 * methods. The subnode can be of type leaf, leaf-list, list,
\r
1042 * container, choice.
\r
1043 * @param childOf parent type
\r
1044 * @param schemaNodes
\r
1045 * set of data schema nodes which are the children of the node
\r
1046 * for which <code>typeBuilder</code> was created
\r
1047 * @return generated type builder which is the same object as the input
\r
1048 * parameter <code>typeBuilder</code>. The getter method could be
\r
1051 private def GeneratedTypeBuilder augSchemaNodeToMethods(Module module, String basePackageName,
1052 GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Set<DataSchemaNode> schemaNodes) {
1053 if ((schemaNodes !== null) && (typeBuilder !== null)) {
1054 for (schemaNode : schemaNodes) {
1055 if (!schemaNode.isAugmenting()) {
1056 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module);
1064 * Adds to <code>typeBuilder</code> a method which is derived from
\r
1065 * <code>schemaNode</code>.
\r
1067 * @param basePackageName
\r
1068 * string with the module package name
\r
1070 * data schema node which is added to <code>typeBuilder</code> as
\r
1072 * @param typeBuilder
\r
1073 * generated type builder to which is <code>schemaNode</code>
\r
1074 * added as a method.
\r
1075 * @param childOf parent type
\r
1076 * @param module current module
\r
1078 private def void addSchemaNodeToBuilderAsMethod(String basePackageName, DataSchemaNode node,
1079 GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Module module) {
1080 if (node !== null && typeBuilder !== null) {
1082 case node instanceof LeafSchemaNode:
1083 resolveLeafSchemaNodeAsMethod(typeBuilder, node as LeafSchemaNode)
1084 case node instanceof LeafListSchemaNode:
1085 resolveLeafListSchemaNode(typeBuilder, node as LeafListSchemaNode)
1086 case node instanceof ContainerSchemaNode:
1087 containerToGenType(module, basePackageName, typeBuilder, childOf, node as ContainerSchemaNode)
1088 case node instanceof ListSchemaNode:
1089 listToGenType(module, basePackageName, typeBuilder, childOf, node as ListSchemaNode)
1090 case node instanceof ChoiceNode:
1091 choiceToGeneratedType(module, basePackageName, typeBuilder, node as ChoiceNode)
1097 * Converts <code>choiceNode</code> to the list of generated types for
\r
1098 * choice and its cases.
\r
1100 * The package names for choice and for its cases are created as
\r
1101 * concatenation of the module package (<code>basePackageName</code>) and
\r
1102 * names of all parents node.
\r
1104 * @param module current module
\r
1105 * @param basePackageName
\r
1106 * string with the module package name
\r
1107 * @param parent parent type
\r
1108 * @param childOf concrete parent for case child nodes
\r
1109 * @param choiceNode
\r
1110 * choice node which is mapped to generated type. Also child
\r
1111 * nodes - cases are mapped to generated types.
\r
1112 * @throws IllegalArgumentException
\r
1114 * <li>if <code>basePackageName</code> equals null</li>
\r
1115 * <li>if <code>choiceNode</code> equals null</li>
\r
1119 private def void choiceToGeneratedType(Module module, String basePackageName, GeneratedTypeBuilder parent,
1120 ChoiceNode choiceNode) {
1121 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1122 checkArgument(choiceNode !== null, "Choice Schema Node cannot be NULL.");
1124 val packageName = packageNameForGeneratedType(basePackageName, choiceNode.path);
1125 val choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
1126 constructGetter(parent, choiceNode.QName.localName, choiceNode.description, choiceTypeBuilder);
1127 choiceTypeBuilder.addImplementsType(DataContainer.typeForClass);
1128 genCtx.get(module).addChildNodeType(choiceNode.path, choiceTypeBuilder)
1129 generateTypesFromChoiceCases(module, basePackageName, parent, choiceTypeBuilder.toInstance, choiceNode);
1133 * Converts <code>caseNodes</code> set to list of corresponding generated
\r
1136 * For every <i>case</i> which isn't added through augment or <i>uses</i> is
\r
1137 * created generated type builder. The package names for the builder is
\r
1138 * created as concatenation of the module package (
\r
1139 * <code>basePackageName</code>) and names of all parents nodes of the
\r
1140 * concrete <i>case</i>. There is also relation "<i>implements type</i>"
\r
1141 * between every case builder and <i>choice</i> type
\r
1143 * @param basePackageName
\r
1144 * string with the module package name
\r
1145 * @param refChoiceType
\r
1146 * type which represents superior <i>case</i>
\r
1147 * @param caseNodes
\r
1148 * set of choice case nodes which are mapped to generated types
\r
1149 * @return list of generated types for <code>caseNodes</code>.
\r
1150 * @throws IllegalArgumentException
\r
1152 * <li>if <code>basePackageName</code> equals null</li>
\r
1153 * <li>if <code>refChoiceType</code> equals null</li>
\r
1154 * <li>if <code>caseNodes</code> equals null</li>
\r
1158 private def void generateTypesFromChoiceCases(Module module, String basePackageName,
1159 GeneratedTypeBuilder choiceParent, Type refChoiceType, ChoiceNode choiceNode) {
1160 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1161 checkArgument(refChoiceType !== null, "Referenced Choice Type cannot be NULL.");
1162 checkArgument(choiceNode !== null, "ChoiceNode cannot be NULL.");
1164 val Set<ChoiceCaseNode> caseNodes = choiceNode.cases;
1165 if (caseNodes == null) {
1169 for (caseNode : caseNodes) {
1170 if (caseNode !== null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
1171 val packageName = packageNameForGeneratedType(basePackageName, caseNode.path);
1172 val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
1173 caseTypeBuilder.addImplementsType(refChoiceType);
1174 genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder)
1175 val Set<DataSchemaNode> caseChildNodes = caseNode.childNodes;
1176 if (caseChildNodes !== null) {
1177 val parentNode = choiceNode.parent;
1178 var SchemaNode parent;
1179 if (parentNode instanceof AugmentationSchema) {
1180 val augSchema = parentNode as AugmentationSchema;
1181 val targetPath = augSchema.targetPath;
1182 var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
1183 if (targetSchemaNode instanceof DataSchemaNode &&
1184 (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
1185 targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
1186 if (targetSchemaNode == null) {
1187 throw new NullPointerException(
1188 "Failed to find target node from grouping for augmentation " + augSchema +
1189 " in module " + module.name);
1192 parent = targetSchemaNode as SchemaNode
1194 parent = choiceNode.parent as SchemaNode;
1196 var GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.path)
1197 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes);
1201 processUsesAugments(caseNode, module);
1206 * Generates list of generated types for all the cases of a choice which are
\r
1207 * added to the choice through the augment.
\r
1210 * @param basePackageName
\r
1211 * string contains name of package to which augment belongs. If
\r
1212 * an augmented choice is from an other package (pcg1) than an
\r
1213 * augmenting choice (pcg2) then case's of the augmenting choice
\r
1214 * will belong to pcg2.
\r
1215 * @param refChoiceType
\r
1216 * Type which represents the choice to which case belongs. Every
\r
1217 * case has to contain its choice in extend part.
\r
1218 * @param caseNodes
\r
1219 * set of choice case nodes for which is checked if are/aren't
\r
1220 * added to choice through augmentation
\r
1221 * @return list of generated types which represents augmented cases of
\r
1222 * choice <code>refChoiceType</code>
\r
1223 * @throws IllegalArgumentException
\r
1225 * <li>if <code>basePackageName</code> equals null</li>
\r
1226 * <li>if <code>refChoiceType</code> equals null</li>
\r
1227 * <li>if <code>caseNodes</code> equals null</li>
\r
1230 private def void generateTypesFromAugmentedChoiceCases(Module module, String basePackageName, Type targetType,
1231 ChoiceNode targetNode, Set<DataSchemaNode> augmentedNodes) {
1232 checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
1233 checkArgument(targetType !== null, "Referenced Choice Type cannot be NULL.");
1234 checkArgument(augmentedNodes !== null, "Set of Choice Case Nodes cannot be NULL.");
1236 for (caseNode : augmentedNodes) {
1237 if (caseNode !== null) {
1238 val packageName = packageNameForGeneratedType(basePackageName, caseNode.path);
1239 val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
1240 caseTypeBuilder.addImplementsType(targetType);
1242 val SchemaNode parent = targetNode.parent as SchemaNode;
1243 var GeneratedTypeBuilder childOfType = null;
1244 if (parent instanceof Module) {
1245 childOfType = genCtx.get(parent as Module).moduleNode
1246 } else if (parent instanceof ChoiceCaseNode) {
1247 childOfType = findCaseByPath(parent.path)
1248 } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) {
1249 childOfType = findChildNodeByPath(parent.path)
1250 } else if (parent instanceof GroupingDefinition) {
1251 childOfType = findGroupingByPath(parent.path);
1254 if (childOfType == null) {
1255 throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode);
1258 if (caseNode instanceof DataNodeContainer) {
1259 val DataNodeContainer dataNodeCase = caseNode as DataNodeContainer;
1260 val Set<DataSchemaNode> childNodes = dataNodeCase.childNodes;
1261 if (childNodes !== null) {
1262 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
1265 val ChoiceCaseNode node = targetNode.getCaseNodeByName(caseNode.getQName().getLocalName());
1266 val Set<DataSchemaNode> childNodes = node.childNodes;
1267 if (childNodes !== null) {
1268 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
1272 genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder)
1279 * Converts <code>leaf</code> to the getter method which is added to
\r
1280 * <code>typeBuilder</code>.
\r
1282 * @param typeBuilder
\r
1283 * generated type builder to which is added getter method as
\r
1284 * <code>leaf</code> mapping
\r
1286 * leaf schema node which is mapped as getter method which is
\r
1287 * added to <code>typeBuilder</code>
\r
1288 * @return boolean value
\r
1290 * <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
\r
1292 * <li>true - in other cases</li>
\r
1295 private def boolean resolveLeafSchemaNodeAsMethod(GeneratedTypeBuilder typeBuilder, LeafSchemaNode leaf) {
1296 if ((leaf !== null) && (typeBuilder !== null)) {
1297 val leafName = leaf.QName.localName;
1298 var String leafDesc = leaf.description;
1299 if (leafDesc === null) {
1303 val parentModule = findParentModule(schemaContext, leaf);
1304 if (leafName !== null && !leaf.isAddedByUses()) {
1305 val TypeDefinition<?> typeDef = leaf.type;
1307 var Type returnType = null;
1308 if (typeDef instanceof EnumTypeDefinition) {
1309 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
1310 val enumTypeDef = typeDef as EnumTypeDefinition;
1311 val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leafName, typeBuilder);
1313 if (enumBuilder !== null) {
1314 returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name);
1316 (typeProvider as TypeProviderImpl).putReferencedType(leaf.path, returnType);
1317 } else if (typeDef instanceof UnionType) {
1318 val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
1319 if (genTOBuilder !== null) {
1320 returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
1322 } else if (typeDef instanceof BitsTypeDefinition) {
1323 val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
1324 if (genTOBuilder !== null) {
1325 returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
1328 val Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
\r
1329 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
1331 if (returnType !== null) {
1332 val MethodSignatureBuilder getter = constructGetter(typeBuilder, leafName, leafDesc, returnType);
1333 processContextRefExtension(leaf, getter, parentModule);
1341 private def void processContextRefExtension(LeafSchemaNode leaf, MethodSignatureBuilder getter, Module module) {
1342 for (node : leaf.unknownSchemaNodes) {
1343 val nodeType = node.nodeType;
1344 if ("context-reference".equals(nodeType.localName)) {
1345 val nodeParam = node.nodeParameter;
1346 var IdentitySchemaNode identity = null;
1347 var String basePackageName = null;
1348 val String[] splittedElement = nodeParam.split(":");
1349 if (splittedElement.length == 1) {
1350 identity = findIdentityByName(module.identities, splittedElement.get(0));
1351 basePackageName = moduleNamespaceToPackageName(module);
1352 } else if (splittedElement.length == 2) {
1353 var prefix = splittedElement.get(0);
1354 val Module dependentModule = findModuleFromImports(module.imports, prefix)
1355 if (dependentModule == null) {
1356 throw new IllegalArgumentException(
1357 "Failed to process context-reference: unknown prefix " + prefix);
1359 identity = findIdentityByName(dependentModule.identities, splittedElement.get(1));
1360 basePackageName = moduleNamespaceToPackageName(dependentModule);
1362 throw new IllegalArgumentException(
1363 "Failed to process context-reference: unknown identity " + nodeParam);
1365 if (identity == null) {
1366 throw new IllegalArgumentException(
1367 "Failed to process context-reference: unknown identity " + nodeParam);
1370 val Class<RoutingContext> clazz = typeof(RoutingContext);
1371 val AnnotationTypeBuilder rc = getter.addAnnotation(clazz.package.name, clazz.simpleName);
1372 val packageName = packageNameForGeneratedType(basePackageName, identity.path);
1373 val genTypeName = parseToClassName(identity.QName.localName);
1374 rc.addParameter("value", packageName + "." + genTypeName + ".class");
1379 private def IdentitySchemaNode findIdentityByName(Set<IdentitySchemaNode> identities, String name) {
1380 for (id : identities) {
1381 if (id.QName.localName.equals(name)) {
1388 private def Module findModuleFromImports(Set<ModuleImport> imports, String prefix) {
1389 for (imp : imports) {
1390 if (imp.prefix.equals(prefix)) {
1391 return schemaContext.findModuleByName(imp.moduleName, imp.revision);
1398 * Converts <code>leaf</code> schema node to property of generated TO
\r
1401 * @param toBuilder
\r
1402 * generated TO builder to which is <code>leaf</code> added as
\r
1405 * leaf schema node which is added to <code>toBuilder</code> as
\r
1407 * @param isReadOnly
\r
1408 * boolean value which says if leaf property is|isn't read only
\r
1409 * @return boolean value
\r
1411 * <li>false - if <code>leaf</code>, <code>toBuilder</code> or leaf
\r
1412 * name equals null or if leaf is added by <i>uses</i>.</li>
\r
1413 * <li>true - other cases</li>
\r
1416 private def boolean resolveLeafSchemaNodeAsProperty(GeneratedTOBuilder toBuilder, LeafSchemaNode leaf,
1417 boolean isReadOnly) {
1418 if ((leaf !== null) && (toBuilder !== null)) {
1419 val leafName = leaf.QName.localName;
1420 var String leafDesc = leaf.description;
1421 if (leafDesc === null) {
1425 if (leafName !== null) {
1426 val TypeDefinition<?> typeDef = leaf.type;
1428 // TODO: properly resolve enum types
\r
1429 val returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
1431 if (returnType !== null) {
1432 val propBuilder = toBuilder.addProperty(parseToClassName(leafName));
1434 propBuilder.setReadOnly(isReadOnly);
1435 propBuilder.setReturnType(returnType);
1436 propBuilder.setComment(leafDesc);
1438 toBuilder.addEqualsIdentity(propBuilder);
1439 toBuilder.addHashIdentity(propBuilder);
1440 toBuilder.addToStringProperty(propBuilder);
1450 * Converts <code>node</code> leaf list schema node to getter method of
\r
1451 * <code>typeBuilder</code>.
\r
1453 * @param typeBuilder
\r
1454 * generated type builder to which is <code>node</code> added as
\r
1457 * leaf list schema node which is added to
\r
1458 * <code>typeBuilder</code> as getter method
\r
1459 * @return boolean value
\r
1461 * <li>true - if <code>node</code>, <code>typeBuilder</code>,
\r
1462 * nodeName equal null or <code>node</code> is added by <i>uses</i></li>
\r
1463 * <li>false - other cases</li>
\r
1466 private def boolean resolveLeafListSchemaNode(GeneratedTypeBuilder typeBuilder, LeafListSchemaNode node) {
1467 if ((node !== null) && (typeBuilder !== null)) {
1468 val nodeName = node.QName.localName;
1469 var String nodeDesc = node.description;
1470 if (nodeDesc === null) {
1473 if (nodeName !== null && !node.isAddedByUses()) {
1474 val TypeDefinition<?> type = node.type;
1475 val listType = Types.listTypeFor(typeProvider.javaTypeForSchemaDefinitionType(type, node));
1476 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
1483 private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode) {
1484 return addDefaultInterfaceDefinition(packageName, schemaNode, null);
1488 * Instantiates generated type builder with <code>packageName</code> and
\r
1489 * <code>schemaNode</code>.
\r
1491 * The new builder always implements
\r
1492 * {@link org.opendaylight.yangtools.yang.binding.DataObject DataObject}.<br />
\r
1493 * If <code>schemaNode</code> is instance of GroupingDefinition it also
\r
1494 * implements {@link org.opendaylight.yangtools.yang.binding.Augmentable
\r
1495 * Augmentable}.<br />
\r
1496 * If <code>schemaNode</code> is instance of
\r
1497 * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
\r
1498 * DataNodeContainer} it can also implement nodes which are specified in
\r
1501 * @param packageName
\r
1502 * string with the name of the package to which
\r
1503 * <code>schemaNode</code> belongs.
\r
1504 * @param schemaNode
\r
1505 * schema node for which is created generated type builder
\r
1506 * @param parent parent type (can be null)
\r
1507 * @return generated type builder <code>schemaNode</code>
\r
1509 private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode,
1511 val builder = addRawInterfaceDefinition(packageName, schemaNode, "");
1512 if (parent === null) {
1513 builder.addImplementsType(DATA_OBJECT);
1515 builder.addImplementsType(BindingTypes.childOf(parent));
1517 if (!(schemaNode instanceof GroupingDefinition)) {
1518 builder.addImplementsType(augmentable(builder));
1521 if (schemaNode instanceof DataNodeContainer) {
1522 addImplementedInterfaceFromUses(schemaNode as DataNodeContainer, builder);
1529 * Wraps the calling of the same overloaded method.
\r
1531 * @param packageName
\r
1532 * string with the package name to which returning generated type
\r
1534 * @param schemaNode
\r
1535 * schema node which provide data about the schema node name
\r
1536 * @return generated type builder for <code>schemaNode</code>
\r
1538 private def GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode) {
1539 return addRawInterfaceDefinition(packageName, schemaNode, "");
1543 * Returns reference to generated type builder for specified
\r
1544 * <code>schemaNode</code> with <code>packageName</code>.
\r
1546 * Firstly the generated type builder is searched in
\r
1547 * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
\r
1548 * found it is created and added to <code>genTypeBuilders</code>.
\r
1550 * @param packageName
\r
1551 * string with the package name to which returning generated type
\r
1553 * @param schemaNode
\r
1554 * schema node which provide data about the schema node name
\r
1555 * @param prefix return type name prefix
\r
1556 * @return generated type builder for <code>schemaNode</code>
\r
1557 * @throws IllegalArgumentException
\r
1559 * <li>if <code>schemaNode</code> equals null</li>
\r
1560 * <li>if <code>packageName</code> equals null</li>
\r
1561 * <li>if Q name of schema node is null</li>
\r
1562 * <li>if schema node name is nul</li>
\r
1566 private def GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode,
1568 checkArgument(schemaNode !== null, "Data Schema Node cannot be NULL.");
1569 checkArgument(packageName !== null, "Package Name for Generated Type cannot be NULL.");
1570 checkArgument(schemaNode.QName !== null, "QName for Data Schema Node cannot be NULL.");
1571 val schemaNodeName = schemaNode.QName.localName;
1572 checkArgument(schemaNodeName !== null, "Local Name of QName for Data Schema Node cannot be NULL.");
1574 var String genTypeName;
1575 if (prefix === null) {
1576 genTypeName = parseToClassName(schemaNodeName);
1578 genTypeName = prefix + parseToClassName(schemaNodeName);
1581 //FIXME: Validation of name conflict
\r
1582 val newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
1583 if (!genTypeBuilders.containsKey(packageName)) {
1584 val Map<String, GeneratedTypeBuilder> builders = new HashMap();
1585 builders.put(genTypeName, newType);
1586 genTypeBuilders.put(packageName, builders);
1588 val Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
1589 if (!builders.containsKey(genTypeName)) {
1590 builders.put(genTypeName, newType);
1597 * Creates the name of the getter method from <code>methodName</code>.
\r
1599 * @param methodName
\r
1600 * string with the name of the getter method
\r
1601 * @param returnType return type
\r
1602 * @return string with the name of the getter method for
\r
1603 * <code>methodName</code> in JAVA method format
\r
1605 private def String getterMethodName(String methodName, Type returnType) {
1606 val method = new StringBuilder();
1607 if (BOOLEAN.equals(returnType)) {
1608 method.append("is");
1610 method.append("get");
1612 method.append(parseToClassName(methodName));
1613 return method.toString();
1617 * Created a method signature builder as part of
\r
1618 * <code>interfaceBuilder</code>.
\r
1620 * The method signature builder is created for the getter method of
\r
1621 * <code>schemaNodeName</code>. Also <code>comment</code> and
\r
1622 * <code>returnType</code> information are added to the builder.
\r
1624 * @param interfaceBuilder
\r
1625 * generated type builder for which the getter method should be
\r
1627 * @param schemaNodeName
\r
1628 * string with schema node name. The name will be the part of the
\r
1629 * getter method name.
\r
1631 * string with comment for the getter method
\r
1632 * @param returnType
\r
1633 * type which represents the return type of the getter method
\r
1634 * @return method signature builder which represents the getter method of
\r
1635 * <code>interfaceBuilder</code>
\r
1637 private def MethodSignatureBuilder constructGetter(GeneratedTypeBuilder interfaceBuilder, String schemaNodeName,
1638 String comment, Type returnType) {
1639 val getMethod = interfaceBuilder.addMethod(getterMethodName(schemaNodeName, returnType));
1640 getMethod.setComment(comment);
1641 getMethod.setReturnType(returnType);
1646 * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
\r
1647 * or to <code>genTOBuilder</code> as property.
\r
1649 * @param basePackageName
\r
1650 * string contains the module package name
\r
1651 * @param schemaNode
\r
1652 * data schema node which should be added as getter method to
\r
1653 * <code>typeBuilder</code> or as a property to
\r
1654 * <code>genTOBuilder</code> if is part of the list key
\r
1655 * @param typeBuilder
\r
1656 * generated type builder for the list schema node
\r
1657 * @param genTOBuilder
\r
1658 * generated TO builder for the list keys
\r
1660 * list of string which contains names of the list keys
\r
1661 * @param module current module
\r
1662 * @throws IllegalArgumentException
\r
1664 * <li>if <code>schemaNode</code> equals null</li>
\r
1665 * <li>if <code>typeBuilder</code> equals null</li>
\r
1668 private def void addSchemaNodeToListBuilders(String basePackageName, DataSchemaNode schemaNode,
1669 GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder, List<String> listKeys, Module module) {
1670 checkArgument(schemaNode !== null, "Data Schema Node cannot be NULL.");
1671 checkArgument(typeBuilder !== null, "Generated Type Builder cannot be NULL.");
1673 if (schemaNode instanceof LeafSchemaNode) {
1674 val leaf = schemaNode as LeafSchemaNode;
1675 val leafName = leaf.QName.localName;
1676 if (!listKeys.contains(leafName)) {
1677 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
1679 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
1681 } else if (!schemaNode.addedByUses) {
1682 if (schemaNode instanceof LeafListSchemaNode) {
1683 resolveLeafListSchemaNode(typeBuilder, schemaNode as LeafListSchemaNode);
1684 } else if (schemaNode instanceof ContainerSchemaNode) {
1685 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, schemaNode as ContainerSchemaNode);
1686 } else if (schemaNode instanceof ChoiceNode) {
1687 choiceToGeneratedType(module, basePackageName, typeBuilder, schemaNode as ChoiceNode);
1688 } else if (schemaNode instanceof ListSchemaNode) {
1689 listToGenType(module, basePackageName, typeBuilder, typeBuilder, schemaNode as ListSchemaNode);
1694 private def typeBuildersToGenTypes(Module module, GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder) {
1695 checkArgument(typeBuilder !== null, "Generated Type Builder cannot be NULL.");
1697 if (genTOBuilder !== null) {
1698 val genTO = genTOBuilder.toInstance();
1699 constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO);
1700 genCtx.get(module).addGeneratedTOBuilder(genTOBuilder)
1705 * Selects the names of the list keys from <code>list</code> and returns
\r
1706 * them as the list of the strings
\r
1709 * of string with names of the list keys
\r
1710 * @return list of string which represents names of the list keys. If the
\r
1711 * <code>list</code> contains no keys then the empty list is
\r
1714 private def listKeys(ListSchemaNode list) {
1715 val List<String> listKeys = new ArrayList();
1717 if (list.keyDefinition !== null) {
1718 val keyDefinitions = list.keyDefinition;
1719 for (keyDefinition : keyDefinitions) {
1720 listKeys.add(keyDefinition.localName);
1727 * Generates for the <code>list</code> which contains any list keys special
\r
1728 * generated TO builder.
\r
1730 * @param packageName
\r
1731 * string with package name to which the list belongs
\r
1733 * list schema node which is source of data about the list name
\r
1734 * @return generated TO builder which represents the keys of the
\r
1735 * <code>list</code> or null if <code>list</code> is null or list of
\r
1736 * key definitions is null or empty.
\r
1738 private def GeneratedTOBuilder resolveListKeyTOBuilder(String packageName, ListSchemaNode list) {
1739 var GeneratedTOBuilder genTOBuilder = null;
1740 if ((list.keyDefinition !== null) && (!list.keyDefinition.isEmpty())) {
1741 if (list !== null) {
1742 val listName = list.QName.localName + "Key";
1743 val String genTOName = parseToClassName(listName);
1744 genTOBuilder = new GeneratedTOBuilderImpl(packageName, genTOName);
1747 return genTOBuilder;
1751 * Builds generated TO builders for <code>typeDef</code> of type
\r
1752 * {@link org.opendaylight.yangtools.yang.model.util.UnionType UnionType} or
\r
1753 * {@link org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
\r
1754 * BitsTypeDefinition} which are also added to <code>typeBuilder</code> as
\r
1755 * enclosing transfer object.
\r
1757 * If more then one generated TO builder is created for enclosing then all
\r
1758 * of the generated TO builders are added to <code>typeBuilder</code> as
\r
1759 * enclosing transfer objects.
\r
1762 * type definition which can be of type <code>UnionType</code> or
\r
1763 * <code>BitsTypeDefinition</code>
\r
1764 * @param typeBuilder
\r
1765 * generated type builder to which is added generated TO created
\r
1766 * from <code>typeDef</code>
\r
1768 * string with name for generated TO builder
\r
1770 * @param parentModule
\r
1771 * @return generated TO builder for <code>typeDef</code>
\r
1773 private def GeneratedTOBuilder addTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
1774 String leafName, LeafSchemaNode leaf, Module parentModule) {
1775 val classNameFromLeaf = parseToClassName(leafName);
1776 val List<GeneratedTOBuilder> genTOBuilders = new ArrayList();
1777 val packageName = typeBuilder.fullyQualifiedName;
1778 if (typeDef instanceof UnionTypeDefinition) {
1779 genTOBuilders.addAll(
1780 (typeProvider as TypeProviderImpl).
1781 provideGeneratedTOBuildersForUnionTypeDef(packageName, (typeDef as UnionTypeDefinition),
1782 classNameFromLeaf, leaf));
1783 } else if (typeDef instanceof BitsTypeDefinition) {
1785 ((typeProvider as TypeProviderImpl) ).
1786 provideGeneratedTOBuilderForBitsTypeDefinition(packageName, typeDef, classNameFromLeaf));
1788 if (genTOBuilders !== null && !genTOBuilders.isEmpty()) {
1789 for (genTOBuilder : genTOBuilders) {
1790 typeBuilder.addEnclosingTransferObject(genTOBuilder);
1792 return genTOBuilders.get(0);
1799 * Adds the implemented types to type builder.
\r
1801 * The method passes through the list of <i>uses</i> in
\r
1802 * {@code dataNodeContainer}. For every <i>use</i> is obtained coresponding
\r
1803 * generated type from {@link BindingGeneratorImpl#allGroupings
\r
1804 * allGroupings} which is added as <i>implements type</i> to
\r
1805 * <code>builder</code>
\r
1807 * @param dataNodeContainer
\r
1808 * element which contains the list of used YANG groupings
\r
1810 * builder to which are added implemented types according to
\r
1811 * <code>dataNodeContainer</code>
\r
1812 * @return generated type builder with all implemented types
\r
1814 private def addImplementedInterfaceFromUses(DataNodeContainer dataNodeContainer, GeneratedTypeBuilder builder) {
1815 for (usesNode : dataNodeContainer.uses) {
1816 if (usesNode.groupingPath !== null) {
1817 val genType = findGroupingByPath(usesNode.groupingPath).toInstance
1818 if (genType === null) {
1819 throw new IllegalStateException(
1820 "Grouping " + usesNode.groupingPath + "is not resolved for " + builder.name);
1822 builder.addImplementsType(genType);
1828 private def GeneratedTypeBuilder findChildNodeByPath(SchemaPath path) {
1829 for (ctx : genCtx.values) {
1830 var result = ctx.getChildNode(path)
1831 if (result !== null) {
1838 private def GeneratedTypeBuilder findGroupingByPath(SchemaPath path) {
1839 for (ctx : genCtx.values) {
1840 var result = ctx.getGrouping(path)
1841 if (result !== null) {
1848 private def GeneratedTypeBuilder findCaseByPath(SchemaPath path) {
1849 for (ctx : genCtx.values) {
1850 var result = ctx.getCase(path)
1851 if (result !== null) {