Added support for discovering YangModuleInfo via ServiceLoader.
[yangtools.git] / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / yangtools / sal / java / api / generator / YangModuleInfoTemplate.xtend
index 3eaf2168f554718ec229b7c217c032111e1d2047..57bcc3bfa79905e55214554f36f81fdca18fd2e3 100644 (file)
  */
 package org.opendaylight.yangtools.sal.java.api.generator
 
-import org.opendaylight.yangtools.yang.model.api.Module
-import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
-import org.opendaylight.yangtools.yang.binding.YangModuleInfo
 import java.io.InputStream
-import com.google.common.collect.ImmutableSet
-import java.util.Map
+import java.io.IOException
+import java.text.DateFormat
+import java.text.SimpleDateFormat
+
+import java.util.Collections
+import java.util.Date
+import java.util.HashSet
 import java.util.LinkedHashMap
+import java.util.Map
+import java.util.Set
+import java.util.TreeMap
+
+import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
 import org.opendaylight.yangtools.binding.generator.util.Types
-import org.opendaylight.yangtools.sal.binding.model.api.Type
 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType
+import org.opendaylight.yangtools.sal.binding.model.api.Type
 import org.opendaylight.yangtools.sal.binding.model.api.WildcardType
-import java.io.IOException
-import java.util.Set
-import java.util.HashSet
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo
+import org.opendaylight.yangtools.yang.model.api.Module
 import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import java.util.Date
-import java.util.TreeMap
-import java.text.DateFormat
-import java.text.SimpleDateFormat
+
+import com.google.common.collect.ImmutableSet
+import static org.opendaylight.yangtools.yang.binding.BindingMapping.*
+import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider
+import com.google.common.base.Preconditions
 
 class YangModuleInfoTemplate {
-    val CLASS = "$YangModuleInfoImpl"
 
     val Module module
     val SchemaContext ctx
     val Map<String, String> importMap = new LinkedHashMap()
 
-    new (Module module, SchemaContext ctx) {
-        if (module == null) {
-            throw new IllegalArgumentException("Module reference cannot be NULL!")
-        }
+    @Property
+    val String packageName;
+
+    @Property
+    val String modelBindingProviderName;
+
+    new(Module module, SchemaContext ctx) {
+        Preconditions.checkArgument(module != null, "Module must not be null.");
         this.module = module
         this.ctx = ctx
+        _packageName = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
+        _modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»''';
     }
 
     def String generate() {
-        val String classBody = body().toString
-        '''
-        package «BindingGeneratorUtil.moduleNamespaceToPackageName(module)» ;
+        val body = '''
+            public final class «MODULE_INFO_CLASS_NAME» implements «YangModuleInfo.importedName» {
 
-        «imports»
+                    private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»();
 
-        «classBody»
+                    private final Set<YangModuleInfo> importedModules;
+
+                    public static «YangModuleInfo.importedName» getInstance() {
+                    return INSTANCE;
+                    }
+
+                    «module.classBody»
+                }
+        '''
+        return '''
+            
+                package «packageName» ;
+                «imports»
+                «body»
         '''.toString
     }
 
-    def body() '''
-        public class «CLASS» implements «YangModuleInfo.importedName» {
-
-            private static final «YangModuleInfo.importedName» INSTANCE = new «CLASS»();
+    def String generateModelProvider() {
+        '''
+            package «packageName»;
 
-            private «CLASS»() {}
+            public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements «YangModelBindingProvider.name» {
 
-            public static «YangModuleInfo.importedName» getInstance() {
-                return INSTANCE;
+                public «YangModuleInfo.name» getModuleInfo() {
+                    return «MODULE_INFO_CLASS_NAME».getInstance();
+                }
             }
+        '''
 
-            «module.classBody»
+    }
 
+    private def CharSequence classBody(Module m) '''
+        private «MODULE_INFO_CLASS_NAME»() {
+            «IF m.imports.size != 0»
+                «Set.importedName»<«YangModuleInfo.importedName»> set = new «HashSet.importedName»<>();
+                «FOR imp : m.imports»
+                    «val name = imp.moduleName»
+                    «val rev = imp.revision»
+                    «IF rev == null»
+                        «val Set<Module> modules = ctx.modules»
+                        «val TreeMap<Date, Module> sorted = new TreeMap()»
+                        «FOR module : modules»
+                            «IF module.name.equals(name)»
+                                «sorted.put(module.revision, module)»
+                            «ENDIF»
+                        «ENDFOR»
+                        set.add(«BindingGeneratorUtil.moduleNamespaceToPackageName(sorted.lastEntry().value)».«MODULE_INFO_CLASS_NAME».getInstance());
+                    «ELSE»
+                        set.add(«BindingGeneratorUtil.moduleNamespaceToPackageName(ctx.findModuleByName(name, rev))».«MODULE_INFO_CLASS_NAME».getInstance());
+                    «ENDIF»
+                «ENDFOR»
+                importedModules = «ImmutableSet.importedName».copyOf(set);
+            «ELSE»
+                importedModules = «Collections.importedName».emptySet();
+            «ENDIF»
+            «InputStream.importedName» stream = «MODULE_INFO_CLASS_NAME».class.getResourceAsStream("«sourcePath»");
+            if (stream == null) {
+                throw new IllegalStateException("Resource «sourcePath» is missing");
+            }
+            try {
+                stream.close();
+            } catch («IOException.importedName» e) {
+            // Resource leak, but there is nothing we can do
+            }
         }
-    '''
 
-    private def CharSequence classBody(Module m) '''
         @Override
-            public «String.importedName» getName() {
+        public «String.importedName» getName() {
             return "«m.name»";
         }
 
@@ -87,38 +143,24 @@ class YangModuleInfoTemplate {
         }
 
         @Override
-        public «InputStream.importedName» getModuleSourceStream() throws «IOException.importedName» {
-            «val path = m.moduleSourcePath»
-            «IF path == null»
-                return null;
-            «ELSE»
-                return «CLASS».class.getResourceAsStream("«path»");
-            «ENDIF»
+        public «InputStream.importedName» getModuleSourceStream() throws IOException {
+            «InputStream.importedName» stream = «MODULE_INFO_CLASS_NAME».class.getResourceAsStream("«sourcePath»");
+            if (stream == null) {
+                throw new «IOException.importedName»("Resource «sourcePath» is missing");
+            }
+            return stream;
         }
 
         @Override
-        public «ImmutableSet.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
-            «Set.importedName»<«YangModuleInfo.importedName»> set = new «HashSet.importedName»<>();
-            «FOR imp : m.imports»
-                «val name = imp.moduleName»
-                «val rev = imp.revision»
-                «IF rev == null»
-                    «val Set<Module> modules = ctx.modules»
-                    «val TreeMap<Date, Module> sorted = new TreeMap()»
-                    «FOR module : modules»
-                        «IF module.name.equals(name)»
-                            «sorted.put(module.revision, module)»
-                        «ENDIF»
-                    «ENDFOR»
-                    set.add(«BindingGeneratorUtil.moduleNamespaceToPackageName(sorted.lastEntry().value)».«CLASS».getInstance());
-                «ELSE»
-                    set.add(«BindingGeneratorUtil.moduleNamespaceToPackageName(ctx.findModuleByName(name, rev))».«CLASS».getInstance());
-                «ENDIF»
-            «ENDFOR»
-            return «ImmutableSet.importedName».copyOf(set);
+        public «Set.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
+            return importedModules;
         }
     '''
 
+    def getSourcePath() {
+        return "/" + module.moduleSourcePath.replace(java.io.File.separatorChar, '/')
+    }
+
     private def imports() ''' 
         «IF !importMap.empty»
             «FOR entry : importMap.entrySet»
@@ -127,7 +169,6 @@ class YangModuleInfoTemplate {
                 «ENDIF»
             «ENDFOR»
         «ENDIF»
-        
     '''
 
     final protected def importedName(Class<?> cls) {
@@ -202,7 +243,7 @@ class YangModuleInfoTemplate {
             return "?";
         }
         val StringBuilder builder = new StringBuilder();
-        
+
         var int i = 0;
         for (pType : pTypes) {
             val Type t = pTypes.get(i)