Specialize relative leafref types during instantiation
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / BuilderImplTemplate.xtend
index 0e2e2085eb3f72a3da438f98253cce282016d3f1..25c07c25c666e102e1b3d418d3a50001970e8af1 100644 (file)
  */
 package org.opendaylight.mdsal.binding.java.api.generator
 
+import static org.opendaylight.mdsal.binding.model.util.Types.STRING;
 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTATION_FIELD
-import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTABLE_AUGMENTATION_NAME
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_EQUALS_NAME
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_HASHCODE_NAME
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_TO_STRING_NAME
 
-import com.google.common.collect.ImmutableMap
-import java.util.Arrays
+import java.util.Collection
 import java.util.List
-import java.util.Map
-import java.util.Objects
+import java.util.Optional
+import org.opendaylight.mdsal.binding.model.api.AnnotationType
 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty
 import org.opendaylight.mdsal.binding.model.api.GeneratedType
+import org.opendaylight.mdsal.binding.model.api.MethodSignature
+import org.opendaylight.mdsal.binding.model.api.MethodSignature.ValueMechanics
 import org.opendaylight.mdsal.binding.model.api.Type
+import org.opendaylight.mdsal.binding.model.util.Types
 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping
-import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.yangtools.yang.binding.AbstractAugmentable
 
 class BuilderImplTemplate extends AbstractBuilderTemplate {
-    val Type builderType;
+    val BuilderTemplate builder;
 
     new(BuilderTemplate builder, GeneratedType type) {
         super(builder.javaType.getEnclosedType(type.identifier), type, builder.targetType, builder.properties,
             builder.augmentType, builder.keyType)
-        this.builderType = builder.type
+        this.builder = builder
     }
 
     override body() '''
-        private static final class «type.name» implements «targetType.importedName» {
+        «targetType.annotations.generateDeprecatedAnnotation»
+        private static final class «type.name»
+            «val impIface = targetType.importedName»
+            «IF augmentType !== null»
+                extends «AbstractAugmentable.importedName»<«impIface»>
+            «ENDIF»
+            implements «impIface» {
 
             «generateFields(true)»
 
-            «generateAugmentField(true)»
+            «generateCopyConstructor(builder.type, type)»
 
-            «generateCopyConstructor(builderType, type)»
-
-            @«Override.importedName»
-            public «Class.importedName»<«targetType.importedName»> getImplementedInterface() {
-                return «targetType.importedName».class;
-            }
-
-            «generateGetters(true)»
+            «generateGetters()»
 
             «generateHashCode()»
 
             «generateEquals()»
 
-            «generateToString(properties)»
+            «generateToString()»
+        }
+    '''
+
+    override generateDeprecatedAnnotation(AnnotationType ann) {
+        return generateAnnotation(ann)
+    }
+
+    def private generateGetters() '''
+        «IF keyType !== null»
+            @«OVERRIDE.importedName»
+            public «keyType.importedName» «BindingMapping.IDENTIFIABLE_KEY_NAME»() {
+                return key;
+            }
+
+        «ENDIF»
+        «IF !properties.empty»
+            «FOR field : properties SEPARATOR '\n'»
+                «field.getterMethod»
+            «ENDFOR»
+        «ENDIF»
+    '''
+
+    private static def Optional<MethodSignature> findGetter(GeneratedType implType, String getterName) {
+        val getter = getterByName(implType.nonDefaultMethods, getterName);
+        if (getter.isPresent) {
+            return getter;
+        }
+        for (ifc : implType.implements) {
+            if (ifc instanceof GeneratedType) {
+                val getterImpl = findGetter(ifc, getterName)
+                if (getterImpl.isPresent) {
+                    return (getterImpl)
+                }
+            }
+        }
+        return Optional.empty
+    }
+
+    override getterMethod(GeneratedProperty field) '''
+        @«OVERRIDE.importedName»
+        public «field.returnType.importedName» «field.getterMethodName»() {
+            «val fieldName = field.fieldName»
+            «IF field.returnType.name.endsWith("[]")»
+                return «fieldName» == null ? null : «fieldName».clone();
+            «ELSE»
+                return «fieldName»;
+            «ENDIF»
         }
     '''
 
+    package def findGetter(String getterName) {
+        val ownGetter = getterByName(type.nonDefaultMethods, getterName);
+        if (ownGetter.isPresent) {
+            return ownGetter.get;
+        }
+        for (ifc : type.implements) {
+            if (ifc instanceof GeneratedType) {
+                val getter = findGetter(ifc, getterName)
+                if (getter.isPresent) {
+                    return (getter.get)
+                }
+            }
+        }
+        throw new IllegalStateException(
+                String.format("%s should be present in %s type or in one of its ancestors as getter",
+                        getterName.propertyNameFromGetter, type));
+    }
+
     /**
      * Template method which generates the method <code>hashCode()</code>.
      *
@@ -64,25 +133,13 @@ class BuilderImplTemplate extends AbstractBuilderTemplate {
             private int hash = 0;
             private volatile boolean hashValid = false;
 
-            @«Override.importedName»
+            @«OVERRIDE.importedName»
             public int hashCode() {
                 if (hashValid) {
                     return hash;
                 }
 
-                final int prime = 31;
-                int result = 1;
-                «FOR property : properties»
-                    «IF property.returnType.name.contains("[")»
-                    result = prime * result + «Arrays.importedName».hashCode(«property.fieldName»);
-                    «ELSE»
-                    result = prime * result + «Objects.importedName».hashCode(«property.fieldName»);
-                    «ENDIF»
-                «ENDFOR»
-                «IF augmentType !== null»
-                    result = prime * result + «Objects.importedName».hashCode(«AUGMENTATION_FIELD»);
-                «ENDIF»
-
+                final int result = «targetType.importedName».«BINDING_HASHCODE_NAME»(this);
                 hash = result;
                 hashValid = true;
                 return result;
@@ -97,53 +154,25 @@ class BuilderImplTemplate extends AbstractBuilderTemplate {
      */
     def protected generateEquals() '''
         «IF !properties.empty || augmentType !== null»
-            @«Override.importedName»
-            public boolean equals(«Object.importedName» obj) {
-                if (this == obj) {
-                    return true;
-                }
-                if (!(obj instanceof «DataObject.importedName»)) {
-                    return false;
-                }
-                if (!«targetType.importedName».class.equals(((«DataObject.importedName»)obj).getImplementedInterface())) {
-                    return false;
-                }
-                «targetType.importedName» other = («targetType.importedName»)obj;
-                «FOR property : properties»
-                    «val fieldName = property.fieldName»
-                    «IF property.returnType.name.contains("[")»
-                    if (!«Arrays.importedName».equals(«fieldName», other.«property.getterMethodName»())) {
-                    «ELSE»
-                    if (!«Objects.importedName».equals(«fieldName», other.«property.getterMethodName»())) {
-                    «ENDIF»
-                        return false;
-                    }
-                «ENDFOR»
-                «IF augmentType !== null»
-                    if (getClass() == obj.getClass()) {
-                        // Simple case: we are comparing against self
-                        «type.name» otherImpl = («type.name») obj;
-                        if (!«Objects.importedName».equals(«AUGMENTATION_FIELD», otherImpl.«AUGMENTATION_FIELD»)) {
-                            return false;
-                        }
-                    } else {
-                        // Hard case: compare our augments with presence there...
-                        for («Map.importedName».Entry<«Class.importedName»<? extends «augmentType.importedName»>, «augmentType.importedName»> e : «AUGMENTATION_FIELD».entrySet()) {
-                            if (!e.getValue().equals(other.«AUGMENTABLE_AUGMENTATION_NAME»(e.getKey()))) {
-                                return false;
-                            }
-                        }
-                        // .. and give the other one the chance to do the same
-                        if (!obj.equals(this)) {
-                            return false;
-                        }
-                    }
-                «ENDIF»
-                return true;
+            @«OVERRIDE.importedName»
+            public boolean equals(«Types.objectType().importedName» obj) {
+                return «targetType.importedName».«BINDING_EQUALS_NAME»(this, obj);
             }
         «ENDIF»
     '''
 
+    /**
+     * Template method which generates the method <code>toString()</code>.
+     *
+     * @return string with the <code>toString()</code> method definition in JAVA format
+     */
+    def protected generateToString() '''
+        @«OVERRIDE.importedName»
+        public «STRING.importedName» toString() {
+            return «targetType.importedName».«BINDING_TO_STRING_NAME»(this);
+        }
+    '''
+
     override protected generateCopyKeys(List<GeneratedProperty> keyProps) '''
         if (base.«BindingMapping.IDENTIFIABLE_KEY_NAME»() != null) {
             this.key = base.«BindingMapping.IDENTIFIABLE_KEY_NAME»();
@@ -155,7 +184,17 @@ class BuilderImplTemplate extends AbstractBuilderTemplate {
         «ENDFOR»
     '''
 
+    override protected CharSequence generateCopyNonKeys(Collection<BuilderGeneratedProperty> props) '''
+        «FOR field : props»
+            «IF field.mechanics === ValueMechanics.NULLIFY_EMPTY»
+                this.«field.fieldName» = «CODEHELPERS.importedName».emptyToNull(base.«field.getterName»());
+            «ELSE»
+                this.«field.fieldName» = base.«field.getterName»();
+            «ENDIF»
+        «ENDFOR»
+    '''
+
     override protected generateCopyAugmentation(Type implType) '''
-        this.«AUGMENTATION_FIELD» = «ImmutableMap.importedName».copyOf(base.«AUGMENTATION_FIELD»);
+        super(base.«AUGMENTATION_FIELD»);
     '''
 }
\ No newline at end of file