Merge "Added export of augmentation schemas to Binding Context"
[yangtools.git] / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / yangtools / sal / java / api / generator / BuilderTemplate.xtend
index 7471406e83b2303e58096658699fc4be1191f9a6..fbe9886d00c375b13ebf9b41cc413a3e50e40833 100644 (file)
@@ -20,38 +20,39 @@ import java.util.Collections\rimport org.opendaylight.yangtools.yang.binding.Data
 import java.util.ArrayList
 import java.util.HashSet
 import java.util.Collection
+import org.opendaylight.yangtools.yang.binding.Identifiable
 
 /**\r
  * Template for generating JAVA builder classes. \r
  */\r
 \r
 class BuilderTemplate extends BaseTemplate {\r
-    \r
+\r
     /**\r
      * Constant with the name of the concrete method.\r
      */\r
     val static GET_AUGMENTATION_METHOD_NAME = "getAugmentation"\r
-    \r
+\r
     /**\r
      * Constant with the suffix for builder classes.\r
      */\r
     val static BUILDER = 'Builder'\r
-    \r
+\r
     /**\r
      * Constant with suffix for the classes which are generated from the builder classes.\r
      */\r
     val static IMPL = 'Impl'\r
-    \r
+\r
     /**\r
      * Generated property is set if among methods is found one with the name GET_AUGMENTATION_METHOD_NAME\r
      */\r
     var GeneratedProperty augmentField\r
-    \r
+\r
     /**\r
      * Set of class attributes (fields) which are derived from the getter methods names\r
      */\r
     val Set<GeneratedProperty> properties\r
-    \r
+\r
     /**\r
      * Constructs new instance of this class.\r
      * @throws IllegalArgumentException if <code>genType</code> equals <code>null</code>\r
@@ -60,7 +61,7 @@ class BuilderTemplate extends BaseTemplate {
         super(genType)\r
         this.properties = propertiesFromMethods(createMethods)\r
     }\r
-    \r
+\r
     /**\r
      * Returns set of method signature instances which contains all the methods of the <code>genType</code>\r
      * and all the methods of the implemented interfaces.\r
@@ -73,7 +74,6 @@ class BuilderTemplate extends BaseTemplate {
         collectImplementedMethods(methods, type.implements)\r
         return methods\r
     }\r
-    \r
 \r
     /**\r
      * Adds to the <code>methods</code> set all the methods of the <code>implementedIfcs</code> \r
@@ -94,12 +94,9 @@ class BuilderTemplate extends BaseTemplate {
             } else if (implementedIfc.fullyQualifiedName == Augmentable.name) {\r
                 for (m : Augmentable.methods) {\r
                     if (m.name == GET_AUGMENTATION_METHOD_NAME) {\r
-                        //addToImports(JAVA_UTIL, HASH_MAP)\r
-                        //addToImports(JAVA_UTIL, MAP)\r
                         val fullyQualifiedName = m.returnType.name\r
                         val pkg = fullyQualifiedName.package\r
                         val name = fullyQualifiedName.name\r
-                        //addToImports(pkg, name)\r
                         val tmpGenTO = new GeneratedTOBuilderImpl(pkg, name)\r
                         val refType = new ReferencedTypeImpl(pkg, name)\r
                         val generic = new ReferencedTypeImpl(type.packageName, type.name)\r
@@ -111,8 +108,7 @@ class BuilderTemplate extends BaseTemplate {
             }\r
         }\r
     }\r
-    \r
-    \r
+\r
     /**\r
      * Returns the first element of the list <code>elements</code>.\r
      * \r
@@ -121,7 +117,7 @@ class BuilderTemplate extends BaseTemplate {
     def private <E> first(List<E> elements) {\r
         elements.get(0)\r
     }\r
-    \r
+\r
     /**\r
      * Returns the name of the package from <code>fullyQualifiedName</code>.\r
      * \r
@@ -143,7 +139,6 @@ class BuilderTemplate extends BaseTemplate {
         val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)\r
         return if (lastDotIndex == -1) fullyQualifiedName else fullyQualifiedName.substring(lastDotIndex + 1)\r
     }\r
-    \r
 \r
     /**\r
      * Creates set of generated property instances from getter <code>methods</code>.\r
@@ -152,8 +147,6 @@ class BuilderTemplate extends BaseTemplate {
      * @return set of generated property instances which represents the getter <code>methods</code>\r
      */\r
     def private propertiesFromMethods(Set<MethodSignature> methods) {\r
-        \r
-\r
         if (methods == null || methods.isEmpty()) {\r
             return Collections.emptySet\r
         }\r
@@ -166,7 +159,7 @@ class BuilderTemplate extends BaseTemplate {
         }\r
         return result\r
     }\r
-    \r
+\r
     /**\r
      * Creates generated property instance from the getter <code>method</code> name and return type.\r
      * \r
@@ -180,7 +173,6 @@ class BuilderTemplate extends BaseTemplate {
      * </ul>\r
      */\r
     def private GeneratedProperty propertyFromGetter(MethodSignature method) {\r
-\r
         if (method == null || method.name == null || method.name.empty || method.returnType == null) {\r
             throw new IllegalArgumentException("Method, method name, method return type reference cannot be NULL or empty!")\r
         }\r
@@ -209,7 +201,7 @@ class BuilderTemplate extends BaseTemplate {
 \r
             «generateConstructorsFromIfcs(type)»\r
 \r
-            «generateSetterFromIfcs(type)»\r
+            «generateMethodFieldsFrom(type)»\r
 \r
             «generateGetters(false)»\r
 \r
@@ -237,88 +229,111 @@ class BuilderTemplate extends BaseTemplate {
         }\r
     '''\r
 \r
+    /**\r
+     * Generate default constructor and constructor for every implemented interface from uses statements.\r
+     */\r
     def private generateConstructorsFromIfcs(Type type) '''\r
         public «type.name»«BUILDER»() {\r
         } \r
         «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»\r
-        «val ifc = type as GeneratedType»\r
-        «FOR impl : ifc.implements»\r
-            «generateConstructorFromIfc(impl)»\r
-        «ENDFOR»\r
+            «val ifc = type as GeneratedType»\r
+            «FOR impl : ifc.implements»\r
+                «generateConstructorFromIfc(impl)»\r
+            «ENDFOR»\r
         «ENDIF»\r
     '''\r
 \r
+    /**\r
+     * Generate constructor with argument of given type.\r
+     */\r
     def private generateConstructorFromIfc(Type impl) '''\r
         «IF (impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)»\r
-        «val implType = impl as GeneratedType»\r
+            «val implType = impl as GeneratedType»\r
 \r
-        public «type.name»«BUILDER»(«implType.fullyQualifiedName» arg) {\r
-            «printConstructorProperties(implType)»\r
-        }\r
-        «FOR implTypeImplement : implType.implements»\r
-            «generateConstructorFromIfc(implTypeImplement)»\r
-        «ENDFOR»\r
+            public «type.name»«BUILDER»(«implType.fullyQualifiedName» arg) {\r
+                «printConstructorPropertySetter(implType)»\r
+            }\r
+            «FOR implTypeImplement : implType.implements»\r
+                «generateConstructorFromIfc(implTypeImplement)»\r
+            «ENDFOR»\r
         «ENDIF»\r
     '''\r
 \r
-    def private printConstructorProperties(Type implementedIfc) '''\r
+    def private printConstructorPropertySetter(Type implementedIfc) '''\r
         «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»\r
-        «val ifc = implementedIfc as GeneratedType»\r
-        «FOR getter : ifc.methodDefinitions»\r
-            this._«getter.propertyNameFromGetter» = arg.«getter.name»();\r
-        «ENDFOR»\r
-        «FOR impl : ifc.implements»\r
-        «printConstructorProperties(impl)»\r
-        «ENDFOR»\r
+            «val ifc = implementedIfc as GeneratedType»\r
+            «FOR getter : ifc.methodDefinitions»\r
+                this._«getter.propertyNameFromGetter» = arg.«getter.name»();\r
+            «ENDFOR»\r
+            «FOR impl : ifc.implements»\r
+                «printConstructorPropertySetter(impl)»\r
+            «ENDFOR»\r
         «ENDIF»\r
     '''\r
 \r
-    def private generateSetterFromIfcs(Type type) '''\r
+    /**\r
+     * Generate 'fieldsFrom' method to set builder properties based on type of given argument.\r
+     */\r
+    def private generateMethodFieldsFrom(Type type) '''\r
         «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»\r
-        «val ifc = type as GeneratedType»\r
-        «val List<Type> done = ifc.getBaseIfcs»\r
-        «generateCommentForSetter(ifc)»\r
-        public void fieldsFrom(«DataObject.importedName» arg) {\r
-            boolean isValidArg = false;\r
-            «FOR impl : ifc.getAllIfcs»\r
-                «generateSettersForIfc(impl, done)»\r
-            «ENDFOR»\r
-            if (!isValidArg) {\r
-                throw new IllegalArgumentException(\r
-                  "expected one of: «ifc.getAllIfcs.toListOfNames» \n" +\r
-                  "but was: " + arg\r
-                );\r
-            }\r
-        }\r
+            «val ifc = type as GeneratedType»\r
+            «IF ifc.hasImplementsFromUses»\r
+                «val List<Type> done = ifc.getBaseIfcs»\r
+                «generateMethodFieldsFromComment(ifc)»\r
+                public void fieldsFrom(«DataObject.importedName» arg) {\r
+                    boolean isValidArg = false;\r
+                    «FOR impl : ifc.getAllIfcs»\r
+                        «generateIfCheck(impl, done)»\r
+                    «ENDFOR»\r
+                    if (!isValidArg) {\r
+                        throw new IllegalArgumentException(\r
+                          "expected one of: «ifc.getAllIfcs.toListOfNames» \n" +\r
+                          "but was: " + arg\r
+                        );\r
+                    }\r
+                }\r
+            «ENDIF»\r
         «ENDIF»\r
     '''\r
 \r
-    def private generateSettersForIfc(Type impl, List<Type> done) '''\r
+    def private generateMethodFieldsFromComment(GeneratedType type) '''\r
+        /**\r
+         Set fields from given grouping argument. Valid argument is instance of one of following types:\r
+         * <ul>\r
+         «FOR impl : type.getAllIfcs»\r
+         * <li>«impl.fullyQualifiedName»</li>\r
+         «ENDFOR»\r
+         * </ul>\r
+         *\r
+         * @param arg grouping object\r
+         * @throws IllegalArgumentException if given argument is none of valid types\r
+        */\r
+    '''\r
+\r
+    /**\r
+     * Method is used to find out if given type implements any interface from uses.\r
+     */\r
+    def boolean hasImplementsFromUses(GeneratedType type) {\r
+        var i = 0\r
+        for (impl : type.getAllIfcs) {\r
+            if ((impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)) {\r
+                i = i + 1\r
+            }\r
+        }\r
+        return i > 0\r
+    }\r
+\r
+    def private generateIfCheck(Type impl, List<Type> done) '''\r
         «IF (impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)»\r
             «val implType = impl as GeneratedType»\r
             if (arg instanceof «implType.fullyQualifiedName») {\r
-                «printSetterProperties(implType)»\r
+                «printPropertySetter(implType)»\r
                 isValidArg = true;\r
             }\r
         «ENDIF»\r
     '''\r
 \r
-    def private generateSettersForNestedIfc(Type impl, List<Type> done) '''\r
-        «IF (impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)»\r
-            «val implType = impl as GeneratedType»\r
-            «val boolean added = done.contains(impl)»\r
-            «IF !(added)»\r
-                if (arg instanceof «implType.fullyQualifiedName») {\r
-                    «printSetterProperties(implType)»\r
-                }\r
-            «ENDIF»\r
-            «FOR implTypeImplement : implType.implements»\r
-                «generateSettersForNestedIfc(implTypeImplement, done)»\r
-            «ENDFOR»\r
-        «ENDIF»\r
-    '''\r
-\r
-    def private printSetterProperties(Type implementedIfc) '''\r
+    def private printPropertySetter(Type implementedIfc) '''\r
         «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»\r
         «val ifc = implementedIfc as GeneratedType»\r
         «FOR getter : ifc.methodDefinitions»\r
@@ -327,20 +342,6 @@ class BuilderTemplate extends BaseTemplate {
         «ENDIF»\r
     '''\r
 \r
-    def private generateCommentForSetter(GeneratedType type) '''\r
-        /**\r
-         Set fields from given grouping argument. Valid argument is instance of one of following types:\r
-         * <ul>\r
-         «FOR impl : type.getAllIfcs»\r
-         * <li>«impl.fullyQualifiedName»</li>\r
-         «ENDFOR»\r
-         * </ul>\r
-         *\r
-         * @param arg grouping object\r
-         * @throws IllegalArgumentException if given argument is none of valid types\r
-        */\r
-    '''\r
-\r
     private def List<Type> getBaseIfcs(GeneratedType type) {\r
         val List<Type> baseIfcs = new ArrayList();\r
         for (ifc : type.implements) {\r
@@ -382,7 +383,7 @@ class BuilderTemplate extends BaseTemplate {
     def private generateFields(boolean _final) '''\r
         «IF !properties.empty»\r
             «FOR f : properties»\r
-                private  «IF _final»final«ENDIF»  «f.returnType.importedName» «f.fieldName»;\r
+                private«IF _final» final«ENDIF» «f.returnType.importedName» «f.fieldName»;\r
             «ENDFOR»\r
         «ENDIF»\r
         «IF augmentField != null»\r
@@ -398,14 +399,14 @@ class BuilderTemplate extends BaseTemplate {
     def private generateSetters() '''\r
         «FOR field : properties SEPARATOR '\n'»\r
             public «type.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.importedName» value) {\r
-                «generateLengthRestrictions(field.returnType, "value")»\r
+                «generateRestrictions(field, "value")»\r
 \r
                 this.«field.fieldName» = value;\r
                 return this;\r
             }\r
         «ENDFOR»\r
         «IF augmentField != null»\r
-            \r
+\r
             public «type.name»«BUILDER» add«augmentField.name.toFirstUpper»(Class<? extends «augmentField.returnType.importedName»> augmentationType, «augmentField.returnType.importedName» augmentation) {\r
                 this.«augmentField.name».put(augmentationType, augmentation);\r
                 return this;\r
@@ -420,17 +421,74 @@ class BuilderTemplate extends BaseTemplate {
      */\r
     def private generateConstructor() '''\r
         private «type.name»«IMPL»(«type.name»«BUILDER» builder) {\r
-            «IF !properties.empty»\r
-                «FOR field : properties»\r
-                    this.«field.fieldName» = builder.«field.getterMethodName»();\r
+            «val allProps = new ArrayList(properties)»\r
+            «val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type))»\r
+            «val keyType = type.getKey»\r
+            «IF isList && keyType != null»\r
+                «val keyProps = new ArrayList((keyType as GeneratedTransferObject).properties)»\r
+                «Collections.sort(keyProps,\r
+                    [ p1, p2 |\r
+                        return p1.name.compareTo(p2.name)\r
+                    ])\r
+                »\r
+                «FOR field : keyProps»\r
+                    «removeProperty(allProps, field.name)»\r
                 «ENDFOR»\r
+                «removeProperty(allProps, "key")»\r
+                if (builder.getKey() == null) {\r
+                    this._key = new «keyType.importedName»(\r
+                        «FOR keyProp : keyProps SEPARATOR ", "»\r
+                            builder.«keyProp.getterMethodName»()\r
+                        «ENDFOR»\r
+                    );\r
+                    «FOR field : keyProps»\r
+                        this.«field.fieldName» = builder.«field.getterMethodName»();\r
+                    «ENDFOR»\r
+                } else {\r
+                    this._key = builder.getKey();\r
+                    «FOR field : keyProps»\r
+                           this.«field.fieldName» = _key.«field.getterMethodName»();\r
+                    «ENDFOR»\r
+                }\r
             «ENDIF»\r
+            «FOR field : allProps»\r
+                this.«field.fieldName» = builder.«field.getterMethodName»();\r
+            «ENDFOR»\r
             «IF augmentField != null»\r
                 this.«augmentField.name».putAll(builder.«augmentField.name»);\r
             «ENDIF»\r
         }\r
     '''\r
-    \r
+\r
+    private def boolean implementsIfc(GeneratedType type, Type impl) {\r
+        for (Type ifc : type.implements) {\r
+            if (ifc.equals(impl)) {\r
+                return true;\r
+            }\r
+        }\r
+        return false;\r
+    }\r
+\r
+    private def Type getKey(GeneratedType type) {\r
+        for (m : type.methodDefinitions) {\r
+            if ("getKey".equals(m.name)) {\r
+                return m.returnType;\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+\r
+    private def void removeProperty(Collection<GeneratedProperty> props, String name) {\r
+        var GeneratedProperty toRemove = null\r
+        for (p : props) {\r
+            if (p.name.equals(name)) {\r
+                toRemove = p;\r
+            }\r
+        }\r
+        if (toRemove != null) {\r
+            props.remove(toRemove);\r
+        }\r
+    }\r
 \r
     /**\r
      * Template method which generate getter methods for IMPL class.\r
@@ -540,6 +598,6 @@ class BuilderTemplate extends BaseTemplate {
         return «type.importedName».class;\r
     }\r
     '''\r
-    \r
+\r
 }\r
 \r