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