Correct YangModuleInfo.getInstance() nullness warning
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / YangModuleInfoTemplate.xtend
1 /*
2  * Copyright (c) 2013 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 package org.opendaylight.mdsal.binding.java.api.generator
9
10 import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.getClassName
11 import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.getRootPackageName
12 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.MODEL_BINDING_PROVIDER_CLASS_NAME
13 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.MODULE_INFO_CLASS_NAME
14 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.MODULE_INFO_QNAMEOF_METHOD_NAME
15
16 import com.google.common.base.Preconditions
17 import com.google.common.collect.ImmutableSet
18 import java.util.Comparator
19 import java.util.HashSet
20 import java.util.Optional
21 import java.util.Set
22 import java.util.TreeMap
23 import java.util.function.Function
24 import org.eclipse.xtend.lib.annotations.Accessors
25 import org.gaul.modernizer_maven_annotations.SuppressModernizer
26 import org.opendaylight.yangtools.yang.binding.YangModuleInfo
27 import org.opendaylight.yangtools.yang.common.Revision
28 import org.opendaylight.yangtools.yang.model.api.Module
29 import org.opendaylight.yangtools.yang.model.api.SchemaContext
30
31 /**
32  * Template for {@link YangModuleInfo} implementation for a particular module. Aside from fulfilling that contract,
33  * this class provides a static {@code createQName(String)} method, which is used by co-generated code to initialize
34  * QNAME constants.
35  */
36 @SuppressModernizer
37 class YangModuleInfoTemplate {
38     static val Comparator<Optional<Revision>> REVISION_COMPARATOR =
39         [ Optional<Revision> first, Optional<Revision> second | Revision.compare(first, second) ]
40
41     // These are always imported. Note we need to import even java.lang members, as there can be conflicting definitions
42     // in our package
43     static val CORE_IMPORT_STR = '''
44         import com.google.common.collect.ImmutableSet;
45         import java.lang.Override;
46         import java.lang.String;
47         import org.eclipse.jdt.annotation.NonNull;
48         import org.opendaylight.yangtools.yang.binding.ResourceYangModuleInfo;
49         import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
50         import org.opendaylight.yangtools.yang.common.QName;
51     '''
52     static val EXT_IMPORT_STR = '''
53         import com.google.common.collect.ImmutableSet;
54         import java.lang.Override;
55         import java.lang.String;
56         import java.util.HashSet;
57         import java.util.Set;
58         import org.eclipse.jdt.annotation.NonNull;
59         import org.opendaylight.yangtools.yang.binding.ResourceYangModuleInfo;
60         import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
61         import org.opendaylight.yangtools.yang.common.QName;
62     '''
63
64     val Module module
65     val SchemaContext ctx
66     val Function<Module, Optional<String>> moduleFilePathResolver
67
68     var importedTypes = CORE_IMPORT_STR
69
70     @Accessors
71     val String packageName
72
73     @Accessors
74     val String modelBindingProviderName
75
76     new(Module module, SchemaContext ctx, Function<Module, Optional<String>> moduleFilePathResolver) {
77         Preconditions.checkArgument(module !== null, "Module must not be null.")
78         this.module = module
79         this.ctx = ctx
80         this.moduleFilePathResolver = moduleFilePathResolver
81         packageName = module.QNameModule.rootPackageName;
82         modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»'''
83     }
84
85     def String generate() {
86         val Set<Module> submodules = new HashSet
87         collectSubmodules(submodules, module)
88
89         val body = '''
90             public final class «MODULE_INFO_CLASS_NAME» extends ResourceYangModuleInfo {
91                 «val rev = module.revision»
92                 private static final @NonNull QName NAME = QName.create("«module.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«module.name»").intern();
93                 private static final @NonNull YangModuleInfo INSTANCE = new «MODULE_INFO_CLASS_NAME»();
94
95                 private final @NonNull ImmutableSet<YangModuleInfo> importedModules;
96
97                 public static @NonNull YangModuleInfo getInstance() {
98                     return INSTANCE;
99                 }
100
101                 public static @NonNull QName «MODULE_INFO_QNAMEOF_METHOD_NAME»(final String localName) {
102                     return QName.create(NAME, localName).intern();
103                 }
104
105                 «classBody(module, MODULE_INFO_CLASS_NAME, submodules)»
106             }
107         '''
108         return '''
109             package «packageName»;
110
111             «importedTypes»
112
113             «body»
114         '''.toString
115     }
116
117     def String generateModelProvider() '''
118         package «packageName»;
119
120         import java.lang.Override;
121         import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider;
122         import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
123
124         public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements YangModelBindingProvider {
125             @Override
126             public YangModuleInfo getModuleInfo() {
127                 return «MODULE_INFO_CLASS_NAME».getInstance();
128             }
129         }
130     '''
131
132     private static def void collectSubmodules(Set<Module> dest, Module module) {
133         for (Module submodule : module.submodules) {
134             if (dest.add(submodule)) {
135                 collectSubmodules(dest, submodule)
136             }
137         }
138     }
139
140     private def CharSequence classBody(Module m, String className, Set<Module> submodules) '''
141         private «className»() {
142             «IF !m.imports.empty || !submodules.empty»
143                 «extendImports»
144                 Set<YangModuleInfo> set = new HashSet<>();
145             «ENDIF»
146             «IF !m.imports.empty»
147                 «FOR imp : m.imports»
148                     «val name = imp.moduleName»
149                     «val rev = imp.revision»
150                     «IF !rev.present»
151                         «val Set<Module> modules = ctx.modules»
152                         «val TreeMap<Optional<Revision>, Module> sorted = new TreeMap(REVISION_COMPARATOR)»
153                         «FOR module : modules»
154                             «IF module.name.equals(name)»
155                                 «sorted.put(module.revision, module)»
156                             «ENDIF»
157                         «ENDFOR»
158                         set.add(«sorted.lastEntry().value.QNameModule.rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
159                     «ELSE»
160                         set.add(«(ctx.findModule(name, rev).get.QNameModule).rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
161                     «ENDIF»
162                 «ENDFOR»
163             «ENDIF»
164             «FOR submodule : submodules»
165                 set.add(«submodule.name.className»Info.getInstance());
166             «ENDFOR»
167             «IF m.imports.empty && submodules.empty»
168                 importedModules = ImmutableSet.of();
169             «ELSE»
170                 importedModules = ImmutableSet.copyOf(set);
171             «ENDIF»
172         }
173
174         @Override
175         public QName getName() {
176             return NAME;
177         }
178
179         @Override
180         protected String resourceName() {
181             return "«sourcePath(m)»";
182         }
183
184         @Override
185         public ImmutableSet<YangModuleInfo> getImportedModules() {
186             return importedModules;
187         }
188         «generateSubInfo(submodules)»
189     '''
190
191     private def void extendImports() {
192         importedTypes = EXT_IMPORT_STR
193     }
194
195     private def sourcePath(Module module) {
196         val opt = moduleFilePathResolver.apply(module)
197         Preconditions.checkState(opt.isPresent, "Module %s does not have a file path", module)
198         return opt.get
199     }
200
201     private def generateSubInfo(Set<Module> submodules) '''
202         «FOR submodule : submodules»
203             «val className = submodule.name.className»
204
205             private static final class «className»Info extends ResourceYangModuleInfo {
206                 «val rev = submodule.revision»
207                 private final @NonNull QName NAME = QName.create("«submodule.namespace.toString»", «
208                 IF rev.present»"«rev.get.toString»", «ENDIF»"«submodule.name»").intern();
209                 private static final @NonNull YangModuleInfo INSTANCE = new «className»Info();
210
211                 private final @NonNull ImmutableSet<YangModuleInfo> importedModules;
212
213                 public static @NonNull YangModuleInfo getInstance() {
214                     return INSTANCE;
215                 }
216
217                 «classBody(submodule, className + "Info", ImmutableSet.of)»
218             }
219         «ENDFOR»
220     '''
221 }