Binding generator v2 - Notifications
[mdsal.git] / binding2 / mdsal-binding2-generator-impl / src / main / java / org / opendaylight / mdsal / binding / javav2 / generator / impl / ModuleToGenType.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.mdsal.binding.javav2.generator.impl;
10
11 import static com.google.common.base.Preconditions.checkArgument;
12 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createDescription;
13 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.groupingsToGenTypes;
14 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.moduleTypeBuilder;
15 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.resolveNotification;
16 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.NOTIFICATION_LISTENER;
17
18 import com.google.common.annotations.Beta;
19 import com.google.common.base.Preconditions;
20 import com.google.common.collect.ImmutableSet;
21 import java.util.Collection;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
26 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
27 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
28 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
29 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
30 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.Module;
32 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
33 import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer;
34 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
35 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
36 import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
37
38 @Beta
39 final class ModuleToGenType {
40
41     private ModuleToGenType() {
42         throw new UnsupportedOperationException("Utility class");
43     }
44
45     static Map<Module, ModuleContext> generate(final Module module, final Map<String, Map<String, GeneratedTypeBuilder>>
46             genTypeBuilders, final SchemaContext schemaContext, final TypeProvider typeProvider, Map<Module,
47             ModuleContext> genCtx, final boolean verboseClassComments) {
48
49         genCtx.put(module, new ModuleContext());
50         genCtx = allTypeDefinitionsToGenTypes(module, genCtx, typeProvider);
51         genCtx = groupingsToGenTypes(module, module.getGroupings(), genCtx, schemaContext, verboseClassComments,
52                 genTypeBuilders, typeProvider);
53         genCtx = actionsAndRPCMethodsToGenType(module, genCtx, schemaContext, verboseClassComments,
54                 genTypeBuilders, typeProvider);
55         genCtx = notificationsToGenType(module, genCtx, schemaContext, genTypeBuilders, verboseClassComments, typeProvider);
56
57         //TODO: call generate for other entities (identities)
58
59         if (!module.getChildNodes().isEmpty()) {
60             final GeneratedTypeBuilder moduleType = GenHelperUtil.moduleToDataType(module, genCtx, verboseClassComments);
61             genCtx.get(module).addModuleNode(moduleType);
62             final String basePackageName = BindingMapping.getRootPackageName(module);
63             GenHelperUtil.resolveDataSchemaNodes(module, basePackageName, moduleType, moduleType, module
64                     .getChildNodes(), genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
65         }
66
67         return genCtx;
68     }
69
70     /**
71      * Converts all extended type definitions of module to the list of
72      * <code>Type</code> objects.
73      *
74      * @param module
75      *            module from which is obtained set of type definitions
76      * @throws IllegalArgumentException
77      *             <ul>
78      *             <li>if module is null</li>
79      *             <li>if name of module is null</li>
80      *             </ul>
81      * @throws IllegalStateException
82      *             if set of type definitions from module is null
83      */
84     private static Map<Module, ModuleContext> allTypeDefinitionsToGenTypes(final Module module, final Map<Module, ModuleContext> genCtx,
85             final TypeProvider typeProvider) {
86         Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
87         Preconditions.checkArgument(module.getName() != null, "Module name cannot be NULL.");
88         final DataNodeIterator it = new DataNodeIterator(module);
89         final List<TypeDefinition<?>> typeDefinitions = it.allTypedefs();
90         Preconditions.checkState(typeDefinitions != null, "Type Definitions for module «module.name» cannot be NULL.");
91
92         typeDefinitions.stream().filter(typedef -> typedef != null).forEach(typedef -> {
93             final Type type = ((TypeProviderImpl) typeProvider).generatedTypeForExtendedDefinitionType(typedef,
94                     typedef);
95             if (type != null) {
96                 final ModuleContext ctx = genCtx.get(module);
97                 ctx.addTypedefType(typedef.getPath(), type);
98                 ctx.addTypeToSchema(type, typedef);
99             }
100         });
101         return genCtx;
102     }
103
104     private static Map<Module, ModuleContext> actionsAndRPCMethodsToGenType(final Module module, Map<Module,
105             ModuleContext> genCtx, final SchemaContext schemaContext, final boolean verboseClassComments,
106             final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
107
108         genCtx = RpcActionGenHelper.rpcMethodsToGenType(module, genCtx, schemaContext, verboseClassComments,
109                 genTypeBuilders, typeProvider);
110         genCtx = RpcActionGenHelper.actionMethodsToGenType(module, genCtx, schemaContext, verboseClassComments,
111                 genTypeBuilders, typeProvider);
112
113         return genCtx;
114     }
115
116     /**
117      * Converts all <b>notifications</b> of the module to the list of
118      * <code>Type</code> objects. In addition are to this list added containers
119      * and lists which are part of this notification.
120      *
121      * @param module
122      *            module from which is obtained set of all notification objects
123      *            to iterate over them
124      * @throws IllegalArgumentException
125      *             <ul>
126      *             <li>if the module equals null</li>
127      *             <li>if the name of module equals null</li>
128      *             </ul>
129      * @throws IllegalStateException
130      *             if set of notifications from module is null
131      */
132     private static Map<Module, ModuleContext> notificationsToGenType(final Module module, final Map<Module, ModuleContext> genCtx,
133             final SchemaContext schemaContext, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
134             final boolean verboseClassComments, final TypeProvider typeProvider) {
135         checkArgument(module != null, "Module reference cannot be NULL.");
136         checkArgument(module.getName() != null, "Module name cannot be NULL.");
137         final Set<NotificationDefinition> notifications = module.getNotifications();
138         if (notifications.isEmpty()) {
139             return genCtx;
140         }
141
142         final GeneratedTypeBuilder listenerInterface = moduleTypeBuilder(module, "Listener", verboseClassComments);
143         listenerInterface.addImplementsType(NOTIFICATION_LISTENER);
144         final String basePackageName = BindingMapping.getRootPackageName(module);
145
146         for (final NotificationDefinition notification : notifications) {
147             if (notification != null) {
148                 resolveNotification(listenerInterface, null, basePackageName, notification, module, schemaContext,
149                         verboseClassComments, genTypeBuilders, typeProvider, genCtx);
150             }
151         }
152
153         //YANG 1.1 allows notifications be tied to containers and lists
154         final Collection<DataSchemaNode> potentials = module.getChildNodes();
155         Set<NotificationDefinition> tiedNotifications = null;
156
157         for (final DataSchemaNode potential : potentials) {
158             if (potential instanceof NotificationNodeContainer) {
159                 tiedNotifications = ((NotificationNodeContainer) potential)
160                         .getNotifications();
161                 for (final NotificationDefinition tiedNotification: tiedNotifications) {
162                     if (tiedNotification != null) {
163                         resolveNotification(listenerInterface, potential.getQName().getLocalName(), basePackageName,
164                                 tiedNotification, module, schemaContext, verboseClassComments, genTypeBuilders,
165                                 typeProvider, genCtx);
166                     }
167                 }
168             }
169         }
170
171         if (tiedNotifications != null) {
172             listenerInterface.setDescription(createDescription(ImmutableSet.<NotificationDefinition>builder()
173                 .addAll(notifications).addAll(tiedNotifications).build(), module, verboseClassComments));
174         } else {
175             listenerInterface.setDescription(createDescription(notifications, module, verboseClassComments));
176         }
177
178         genCtx.get(module).addTopLevelNodeType(listenerInterface);
179
180         return genCtx;
181     }
182 }