Extend BindingNamespaceType
[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.GenHelperUtil.groupingsToGenTypes;
13 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.moduleTypeBuilder;
14 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.processUsesImplements;
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.Objects;
25 import java.util.Set;
26 import org.opendaylight.mdsal.binding.javav2.generator.context.ModuleContext;
27 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
28 import org.opendaylight.mdsal.binding.javav2.generator.util.TypeComments;
29 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
30 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
31 import org.opendaylight.mdsal.binding.javav2.model.api.YangSourceDefinition;
32 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
33 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
34 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
35 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.Module;
38 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
39 import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer;
40 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
41 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
42 import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
43
44 @Beta
45 final class ModuleToGenType {
46
47     private ModuleToGenType() {
48         throw new UnsupportedOperationException("Utility class");
49     }
50
51     static Map<Module, ModuleContext> generate(final Module module, final Map<String, Map<String, GeneratedTypeBuilder>>
52             genTypeBuilders, final SchemaContext schemaContext, final TypeProvider typeProvider, Map<Module,
53             ModuleContext> genCtx, final boolean verboseClassComments) {
54
55         genCtx.put(module, new ModuleContext());
56         genCtx = allTypeDefinitionsToGenTypes(module, genCtx, typeProvider);
57         genCtx = groupingsToGenTypes(module, module.getGroupings(), genCtx, schemaContext, verboseClassComments,
58                 genTypeBuilders, typeProvider);
59         genCtx = allIdentitiesToGenTypes(module, schemaContext, genCtx, verboseClassComments,  genTypeBuilders, typeProvider);
60
61         if (!module.getChildNodes().isEmpty()) {
62             final GeneratedTypeBuilder moduleType = GenHelperUtil.moduleToDataType(module, genCtx, verboseClassComments);
63             genCtx.get(module).addModuleNode(moduleType);
64             final String basePackageName = BindingMapping.getRootPackageName(module);
65             GenHelperUtil.resolveDataSchemaNodes(module, basePackageName, moduleType, moduleType, module
66                     .getChildNodes(), genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider,
67                     BindingNamespaceType.Data);
68             processUsesImplements(module, module, schemaContext, genCtx, BindingNamespaceType.Data);
69         }
70
71         genCtx = notificationsToGenType(module, genCtx, schemaContext, genTypeBuilders, verboseClassComments, typeProvider);
72
73         //after potential parent data schema nodes
74         genCtx = actionsAndRPCMethodsToGenType(module, genCtx, schemaContext, verboseClassComments,
75                 genTypeBuilders, typeProvider);
76
77         return genCtx;
78     }
79
80     /**
81      * Converts all extended type definitions of module to the list of
82      * <code>Type</code> objects.
83      *
84      * @param module
85      *            module from which is obtained set of type definitions
86      * @throws IllegalArgumentException
87      *             <ul>
88      *             <li>if module is null</li>
89      *             <li>if name of module is null</li>
90      *             </ul>
91      * @throws IllegalStateException
92      *             if set of type definitions from module is null
93      */
94     private static Map<Module, ModuleContext> allTypeDefinitionsToGenTypes(final Module module, final Map<Module, ModuleContext> genCtx,
95             final TypeProvider typeProvider) {
96         Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
97         Preconditions.checkArgument(module.getName() != null, "Module name cannot be NULL.");
98         final DataNodeIterator it = new DataNodeIterator(module);
99         final List<TypeDefinition<?>> typeDefinitions = it.allTypedefs();
100         Preconditions.checkState(typeDefinitions != null, "Type Definitions for module «module.name» cannot be NULL.");
101
102         typeDefinitions.stream().filter(Objects::nonNull).forEach(typedef -> {
103             final Type type = ((TypeProviderImpl) typeProvider).generatedTypeForExtendedDefinitionType(typedef,
104                     typedef);
105             if (type != null) {
106                 final ModuleContext ctx = genCtx.get(module);
107                 ctx.addTypedefType(typedef.getPath(), type);
108                 ctx.addTypeToSchema(type, typedef);
109             }
110         });
111         return genCtx;
112     }
113
114     private static Map<Module, ModuleContext> actionsAndRPCMethodsToGenType(final Module module, Map<Module,
115             ModuleContext> genCtx, final SchemaContext schemaContext, final boolean verboseClassComments,
116             final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
117
118         genCtx = RpcActionGenHelper.rpcMethodsToGenType(module, genCtx, schemaContext, verboseClassComments,
119                 genTypeBuilders, typeProvider);
120         genCtx = RpcActionGenHelper.actionMethodsToGenType(module, genCtx, schemaContext, verboseClassComments,
121                 genTypeBuilders, typeProvider);
122
123         return genCtx;
124     }
125
126     /**
127      * Converts all <b>identities</b> of the module to the list of
128      * <code>Type</code> objects.
129      *
130      * @param module
131      *            module from which is obtained set of all identity objects to
132      *            iterate over them
133      * @param schemaContext
134      *            schema context only used as input parameter for method
135      *            {@link GenHelperUtil#identityToGenType(Module, String, IdentitySchemaNode, SchemaContext, Map, boolean)}
136      * @param genCtx generated context
137      * @return returns generated context
138      *
139      */
140     private static Map<Module, ModuleContext> allIdentitiesToGenTypes(final Module module,
141             final SchemaContext schemaContext, Map<Module, ModuleContext> genCtx, boolean verboseClassComments,
142             final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
143
144         final Set<IdentitySchemaNode> schemaIdentities = module.getIdentities();
145         final String basePackageName = BindingMapping.getRootPackageName(module);
146
147         if (schemaIdentities != null && !schemaIdentities.isEmpty()) {
148             for (final IdentitySchemaNode identity : schemaIdentities) {
149                 GenHelperUtil.identityToGenType(module, basePackageName, identity, schemaContext, genCtx,
150                     verboseClassComments);
151             }
152         }
153
154         return genCtx;
155     }
156
157     /**
158      * Converts all <b>notifications</b> of the module to the list of
159      * <code>Type</code> objects. In addition are to this list added containers
160      * and lists which are part of this notification.
161      *
162      * @param module
163      *            module from which is obtained set of all notification objects
164      *            to iterate over them
165      * @throws IllegalArgumentException
166      *             <ul>
167      *             <li>if the module equals null</li>
168      *             <li>if the name of module equals null</li>
169      *             </ul>
170      * @throws IllegalStateException
171      *             if set of notifications from module is null
172      */
173     private static Map<Module, ModuleContext> notificationsToGenType(final Module module, final Map<Module, ModuleContext> genCtx,
174             final SchemaContext schemaContext, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
175             final boolean verboseClassComments, final TypeProvider typeProvider) {
176         checkArgument(module != null, "Module reference cannot be NULL.");
177         checkArgument(module.getName() != null, "Module name cannot be NULL.");
178         final Set<NotificationDefinition> notifications = module.getNotifications();
179         if (notifications.isEmpty()) {
180             return genCtx;
181         }
182
183         final GeneratedTypeBuilder listenerInterface = moduleTypeBuilder(module, "Listener", verboseClassComments,
184                 genCtx.get(module));
185         listenerInterface.addImplementsType(NOTIFICATION_LISTENER);
186         final String basePackageName = BindingMapping.getRootPackageName(module);
187
188         for (final NotificationDefinition notification : notifications) {
189             if (notification != null) {
190                 resolveNotification(listenerInterface, null, basePackageName, notification, module, schemaContext,
191                         verboseClassComments, genTypeBuilders, typeProvider, genCtx);
192                 processUsesImplements(notification, module, schemaContext, genCtx, BindingNamespaceType.Notification);
193             }
194         }
195
196         //YANG 1.1 allows notifications be tied to containers and lists
197         final Collection<DataSchemaNode> potentials = module.getChildNodes();
198         Set<NotificationDefinition> tiedNotifications = null;
199
200         for (final DataSchemaNode potential : potentials) {
201             if (potential instanceof NotificationNodeContainer) {
202                 tiedNotifications = ((NotificationNodeContainer) potential)
203                         .getNotifications();
204                 for (final NotificationDefinition tiedNotification: tiedNotifications) {
205                     if (tiedNotification != null) {
206                         resolveNotification(listenerInterface, potential.getQName().getLocalName(), basePackageName,
207                                 tiedNotification, module, schemaContext, verboseClassComments, genTypeBuilders,
208                                 typeProvider, genCtx);
209                         processUsesImplements(tiedNotification, module, schemaContext, genCtx, BindingNamespaceType.Notification);
210                     }
211                 }
212             }
213         }
214
215         if (verboseClassComments) {
216             if (tiedNotifications != null) {
217                 YangSourceDefinition.of(module,
218                     ImmutableSet.<NotificationDefinition>builder().addAll(notifications).addAll(tiedNotifications)
219                         .build()).ifPresent(listenerInterface::setYangSourceDefinition);
220             } else {
221                 YangSourceDefinition.of(module, notifications).ifPresent(listenerInterface::setYangSourceDefinition);
222             }
223             listenerInterface.addComment(TypeComments.javadoc(
224                 "Interface for receiving the following YANG notifications defined in module <b>" + module.getName()
225                     + "</b>").get());
226         }
227
228         genCtx.get(module).addTopLevelNodeType(listenerInterface);
229
230         return genCtx;
231     }
232 }