String performance and maintenability
[controller.git] / opendaylight / config / yang-jmx-generator-plugin / src / main / java / org / opendaylight / controller / config / yangjmxgenerator / plugin / gofactory / AbsModuleGeneratedObjectFactory.java
index 2378fac6e710a2aa8ee5df1e2688272b8bb0bd1e..044431844da4da47dc2ad3b2c50d255951f41777 100644 (file)
@@ -12,7 +12,10 @@ import static java.lang.String.format;
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Optional;
-import java.util.ArrayList;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -25,8 +28,10 @@ import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractModuleTemplate;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.IdentityRefModuleField;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Method;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.MethodDefinition;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject;
@@ -45,10 +50,16 @@ public class AbsModuleGeneratedObjectFactory {
         AbstractModuleTemplate abstractModuleTemplate = TemplateFactory.abstractModuleTemplateFromMbe(mbe);
         Optional<String> header = abstractModuleTemplate.getHeaderString();
 
-        List<FullyQualifiedName> implementedInterfaces = new ArrayList<>();
-        for(String implemented: abstractModuleTemplate.getTypeDeclaration().getImplemented()) {
-            implementedInterfaces.add(FullyQualifiedName.fromString(implemented));
-        }
+        List<FullyQualifiedName> implementedInterfaces =
+                Lists.transform(abstractModuleTemplate.getTypeDeclaration().getImplemented(),
+                        FullyQualifiedName::fromString);
+
+        Optional<FullyQualifiedName> extended =
+                Optional.fromNullable(
+                        Iterables.getFirst(
+                                Collections2.transform(abstractModuleTemplate.getTypeDeclaration().getExtended(),
+                                        FullyQualifiedName::fromString), null));
+
         Optional<FullyQualifiedName> maybeRegistratorType;
         if (abstractModuleTemplate.isRuntime()) {
             maybeRegistratorType = Optional.of(FullyQualifiedName.fromString(abstractModuleTemplate.getRegistratorType()));
@@ -56,7 +67,7 @@ public class AbsModuleGeneratedObjectFactory {
             maybeRegistratorType = Optional.absent();
         }
 
-        return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, implementedInterfaces,
+        return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, extended, implementedInterfaces,
                 abstractModuleTemplate.getModuleFields(), maybeRegistratorType, abstractModuleTemplate.getMethods(),
                 mbe.getYangModuleQName());
     }
@@ -65,6 +76,7 @@ public class AbsModuleGeneratedObjectFactory {
                                              Optional<String> copyright,
                                              Optional<String> header,
                                              Optional<String> classJavaDoc,
+                                             Optional<FullyQualifiedName> extended,
                                              List<FullyQualifiedName> implementedInterfaces,
                                              List<ModuleField> moduleFields,
                                              Optional<FullyQualifiedName> maybeRegistratorType,
@@ -84,12 +96,15 @@ public class AbsModuleGeneratedObjectFactory {
         for(FullyQualifiedName implemented: implementedInterfaces) {
             b.addImplementsFQN(implemented);
         }
+        if(extended.isPresent()) {
+            b.addExtendsFQN(extended.get());
+        }
         if (classJavaDoc.isPresent()) {
             b.addClassAnnotation(format("@%s(value=\"%s\")", Description.class.getCanonicalName(), classJavaDoc.get()));
         }
 
         // add logger:
-        b.addToBody(getLogger(abstractFQN));
+        b.addToBody(getLoggerDefinition(abstractFQN));
 
         b.addToBody("//attributes start");
         for(ModuleField moduleField: moduleFields) {
@@ -99,9 +114,6 @@ public class AbsModuleGeneratedObjectFactory {
         b.addToBody("//attributes end");
 
 
-        b.addToBody(getCommonFields(abstractFQN));
-
-
         b.addToBody(getNewConstructor(abstractFQN));
         b.addToBody(getCopyFromOldConstructor(abstractFQN));
 
@@ -110,29 +122,30 @@ public class AbsModuleGeneratedObjectFactory {
 
         b.addToBody(getCachesOfResolvedDependencies(moduleFields));
         b.addToBody(getCachesOfResolvedIdentityRefs(moduleFields));
-        b.addToBody(getGetInstance(moduleFields));
+        b.addToBody(getResolveDependencies(moduleFields));
         b.addToBody(getReuseLogic(moduleFields, abstractFQN));
         b.addToBody(getEqualsAndHashCode(abstractFQN));
 
         b.addToBody(getMethods(methods));
+        b.addToBody(getGetLogger());
 
         return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
     }
 
     private static String getMethods(List<? extends Method>  methods) {
-        String result = "\n// getters and setters\n";
-        for(Method method: methods) {
-            result += method.toString()+"\n";
+        StringBuilder result = new StringBuilder("\n// getters and setters\n");
+        for (Method method : methods) {
+            result.append(method).append("\n");
         }
-        return result;
+        return result.toString();
     }
 
     private static String getEqualsAndHashCode(FullyQualifiedName abstractFQN) {
         return "\n"+
             "@Override\n"+
             "public boolean equals(Object o) {\n"+
-                "if (this == o) return true;\n"+
-                "if (o == null || getClass() != o.getClass()) return false;\n"+
+                "if (this == o) { return true; }\n"+
+                "if (o == null || getClass() != o.getClass()) { return false; }\n"+
                 format("%s that = (%1$s) o;\n", abstractFQN.getTypeName())+
                 "return identifier.equals(that.identifier);\n"+
             "}\n"+
@@ -144,61 +157,62 @@ public class AbsModuleGeneratedObjectFactory {
     }
 
     private static String getReuseLogic(List<ModuleField> moduleFields, FullyQualifiedName abstractFQN) {
-        String result = "\n"+
-            format("public boolean canReuseInstance(%s oldModule){\n", abstractFQN.getTypeName())+
-                "// allow reusing of old instance if no parameters was changed\n"+
-                "return isSame(oldModule);\n"+
-            "}\n"+
-            "\n"+
-            format("public %s reuseInstance(%1$s oldInstance){\n", AutoCloseable.class.getCanonicalName())+
-                "// implement if instance reuse should be supported. Override canReuseInstance to change the criteria.\n"+
-                "return oldInstance;\n"+
-            "}\n";
+        StringBuilder result = new StringBuilder("\n" +
+                format("public boolean canReuseInstance(%s oldModule){\n", abstractFQN.getTypeName()) +
+                "// allow reusing of old instance if no parameters was changed\n" +
+                "return isSame(oldModule);\n" +
+                "}\n" +
+                "\n" +
+                format("public %s reuseInstance(%1$s oldInstance){\n", AutoCloseable.class.getCanonicalName()) +
+                "// implement if instance reuse should be supported." +
+                "Override canReuseInstance to change the criteria.\n" +
+                "return oldInstance;\n" +
+                "}\n");
         // isSame method that detects changed fields
-        result += "\n"+
-            format("public boolean isSame(%s other) {\n", abstractFQN.getTypeName())+
-                "if (other == null) {\n"+
-                    "throw new IllegalArgumentException(\"Parameter 'other' is null\");\n"+
-                "}\n";
-        // loop through fields, do deep equals on each field
+        result.append("\n")
+                .append(format("public boolean isSame(%s other) {\n", abstractFQN.getTypeName()))
+                .append("if (other == null) {\n")
+                .append("throw new IllegalArgumentException(\"Parameter 'other' is null\");\n")
+                .append("}\n");
 
+        // loop through fields, do deep equals on each field
         for (ModuleField moduleField : moduleFields) {
+            result.append(format(
+                    "if (!java.util.Objects.deepEquals(%s, other.%1$s)) {\n" +
+                            "return false;\n" +
+                            "}\n", moduleField.getName()));
+
             if (moduleField.isListOfDependencies()) {
-                result += format(
-                    "if (%1$sDependency.equals(other.%1$sDependency) == false) {\n"+
-                        "return false;\n"+
-                    "}\n"+
-                    "for (int idx = 0; idx < %1$sDependency.size(); idx++) {\n"+
-                        "if (%1$sDependency.get(idx) != other.%1$sDependency.get(idx)) {\n"+
-                            "return false;\n"+
-                        "}\n"+
-                    "}\n" ,moduleField.getName());
+                result.append(format(
+                        "for (int idx = 0; idx < %1$s.size(); idx++) {\n" +
+                                "if (!dependencyResolver.canReuseDependency(%1$s.get(idx), %1$sJmxAttribute)) {\n" +
+                                "return false;\n" +
+                                "}\n" +
+                                "}\n", moduleField.getName()));
             } else if (moduleField.isDependent()) {
-                result += format(
-                    "if (%sDependency != other.%1$sDependency) { // reference to dependency must be same\n"+
-                        "return false;\n"+
-                    "}\n",moduleField.getName());
-            } else {
-                result += format(
-                    "if (java.util.Objects.deepEquals(%s, other.%1$s) == false) {\n"+
-                        "return false;\n"+
-                    "}\n", moduleField.getName());
+                result.append(format(
+                        // If a reference is null (ie optional reference) it makes no sens to call canReuse on it
+                        // In such case we continue in the isSame method because if we have null here, the previous
+                        // value was null as well
+                        // If the previous value was not null and current is or vice verse, the deepEquals comparison
+                        // would return false
+                        "if(%1$s!= null) {\n" +
+                                "// reference to dependency must be reusable as well\n" +
+                                "if (!dependencyResolver.canReuseDependency(%1$s, %1$sJmxAttribute)) {\n" +
+                                "return false;\n" +
+                                "}\n" +
+                                "}\n", moduleField.getName()));
             }
         }
-        result += "\n"+
-                "return true;\n"+
-            "}\n";
 
-        return result;
-    }
+        result.append("\n" +
+                "return true;\n" +
+                "}\n");
 
-    private static String getGetInstance(List<ModuleField> moduleFields) {
-        String result = "\n"+
-            "@Override\n"+
-            format("public final %s getInstance() {\n", AutoCloseable.class.getCanonicalName())+
-                "if(instance==null) {\n";
-        // create instance start
+        return result.toString();
+    }
 
+    private static String getResolveDependencies(final List<ModuleField> moduleFields) {
         // loop through dependent fields, use dependency resolver to instantiate dependencies. Do it in loop in case field represents list of dependencies.
         Map<ModuleField, String> resolveDependenciesMap = new HashMap<>();
         for(ModuleField moduleField: moduleFields) {
@@ -207,91 +221,59 @@ public class AbsModuleGeneratedObjectFactory {
                 String osgi = moduleField.getDependency().getSie().getExportedOsgiClassName();
                 if (moduleField.isList()) {
                     str = format(
-                        "%sDependency = new java.util.ArrayList<%s>();\n"+
-                        "for(javax.management.ObjectName dep : %1$s) {\n"+
-                            "%1$sDependency.add(dependencyResolver.resolveInstance(%2$s.class, dep, %1$sJmxAttribute));\n"+
-                        "}\n", moduleField.getName(), osgi);
+                            "%sDependency = new java.util.ArrayList<%s>();\n"+
+                                    "for(javax.management.ObjectName dep : %1$s) {\n"+
+                                    "%1$sDependency.add(dependencyResolver.resolveInstance(%2$s.class, dep, %1$sJmxAttribute));\n"+
+                                    "}\n", moduleField.getName(), osgi);
                 } else {
                     str = format(
-                        "%1$sDependency = dependencyResolver.resolveInstance(%2$s.class, %1$s, %1$sJmxAttribute);\n",
-                        moduleField.getName(), osgi);
+                            "%1$sDependency = dependencyResolver.resolveInstance(%2$s.class, %1$s, %1$sJmxAttribute);\n",
+                            moduleField.getName(), osgi);
                 }
                 resolveDependenciesMap.put(moduleField, str);
             }
         }
 
+        StringBuilder result = new StringBuilder("\n" +
+                "protected final void resolveDependencies() {\n");
         // wrap each field resolvation statement with if !=null when dependency is not mandatory
         for (Map.Entry<ModuleField, String> entry : resolveDependenciesMap.entrySet()) {
-            if (entry.getKey().getDependency().isMandatory() == false) {
+            if (!entry.getKey().getDependency().isMandatory()) {
                 checkState(entry.getValue().endsWith(";\n"));
-                result += format("if (%s!=null) {\n%s}\n", entry.getKey().getName(), entry.getValue());
+                result.append(format("if (%s!=null) {\n%s}\n", entry.getKey().getName(), entry.getValue()));
             } else {
-                result += entry.getValue();
+                result.append(entry.getValue());
             }
         }
 
         // add code to inject dependency resolver to fields that support it
         for(ModuleField moduleField: moduleFields) {
             if (moduleField.isNeedsDepResolver()) {
-                result += format("if (%s!=null){\n", moduleField.getName());
+                result.append(format("if (%s!=null){\n", moduleField.getName()));
                 if (moduleField.isList()) {
-                    result += format(
-                        "for(%s candidate : %s) {\n"+
-                            "candidate.injectDependencyResolver(dependencyResolver);\n"+
-                        "}\n", moduleField.getGenericInnerType(), moduleField.getName());
+                    result.append(format(
+                            "for(%s candidate : %s) {\n" +
+                                    "candidate.injectDependencyResolver(dependencyResolver);\n" +
+                                    "}\n", moduleField.getGenericInnerType(), moduleField.getName()));
                 } else {
-                    result += format("%s.injectDependencyResolver(dependencyResolver);\n", moduleField.getName());
+                    result.append(format("%s.injectDependencyResolver(dependencyResolver);\n", moduleField.getName()));
                 }
-                result += "}\n";
+                result.append("}\n");
             }
         }
 
         // identity refs need to be injected with dependencyResolver and base class
         for (ModuleField moduleField : moduleFields) {
             if (moduleField.isIdentityRef()) {
-                result += format("if (%s!=null) {", moduleField.getName());
-                result += format("set%s(%s.resolveIdentity(dependencyResolver, %s.class));",
+                result.append(format("if (%s!=null) {", moduleField.getName()));
+                result.append(format("set%s(%s.resolveIdentity(dependencyResolver, %s.class));",
                         moduleField.getAttributeName(), moduleField.getName(),
-                        ((IdentityRefModuleField)moduleField).getIdentityBaseClass());
-                result += "}\n";
+                        ((IdentityRefModuleField) moduleField).getIdentityBaseClass()));
+                result.append("}\n");
             }
         }
-
-        // create instance end: reuse and recreate logic
-        result +=   "if(oldInstance!=null && canReuseInstance(oldModule)) {\n"+
-                        "instance = reuseInstance(oldInstance);\n"+
-                    "} else {\n"+
-                        "if(oldInstance!=null) {\n"+
-                           "try {\n"+
-                                "oldInstance.close();\n"+
-                            "} catch(Exception e) {\n"+
-                                "logger.error(\"An error occurred while closing old instance \" + oldInstance, e);\n"+
-                            "}\n"+
-                        "}\n"+
-                        "instance = createInstance();\n"+
-                        "if (instance == null) {\n"+
-                            "throw new IllegalStateException(\"Error in createInstance - null is not allowed as return value\");\n"+
-                        "}\n"+
-                    "}\n"+
-                "}\n"+
-                "return instance;\n"+
-            "}\n"+
-            format("public abstract %s createInstance();\n", AutoCloseable.class.getCanonicalName());
-
-        return result;
-    }
-
-    private static String getCommonFields(FullyQualifiedName abstractFQN) {
-        return "\n"+
-            format("private final %s oldModule;\n", abstractFQN.getTypeName())+
-            format("private final %s oldInstance;\n", AutoCloseable.class.getCanonicalName())+
-            format("private %s instance;\n", AutoCloseable.class.getCanonicalName())+
-            format("protected final %s dependencyResolver;\n", DependencyResolver.class.getCanonicalName())+
-            format("private final %s identifier;\n", ModuleIdentifier.class.getCanonicalName())+
-            "@Override\n"+
-            format("public %s getIdentifier() {\n", ModuleIdentifier.class.getCanonicalName())+
-                "return identifier;\n"+
-            "}\n";
+        result.append("}\n");
+        return result.toString();
     }
 
     private static String getCachesOfResolvedIdentityRefs(List<ModuleField> moduleFields) {
@@ -350,35 +332,43 @@ public class AbsModuleGeneratedObjectFactory {
     }
 
     private static String getValidationMethods(List<ModuleField> moduleFields) {
-        String result = "\n"+
-            "@Override\n"+
-            "public void validate() {\n";
+        StringBuilder result = new StringBuilder("\n" +
+                "@Override\n" +
+                "public void validate() {\n");
         // validate each mandatory dependency
-        for(ModuleField moduleField: moduleFields) {
-            if (moduleField.isDependent() && moduleField.getDependency().isMandatory()) {
+        for (ModuleField moduleField : moduleFields) {
+            if (moduleField.isDependent()) {
                 if (moduleField.isList()) {
-                    result += "" +
-                            format("for(javax.management.ObjectName dep : %s) {\n", moduleField.getName()) +
-                            format("    dependencyResolver.validateDependency(%s.class, dep, %sJmxAttribute);\n",
-                                    moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName()) +
-                            "}\n";
+                    result.append(format("for(javax.management.ObjectName dep : %s) {\n", moduleField.getName()))
+                            .append(format("    dependencyResolver.validateDependency(%s.class, dep, %sJmxAttribute);" +
+                                                    "\n",
+                                            moduleField.getDependency().getSie().getFullyQualifiedName(),
+                                            moduleField.getName()))
+                            .append("}\n");
                 } else {
-                    result += format("dependencyResolver.validateDependency(%s.class, %s, %sJmxAttribute);",
-                            moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName(), moduleField.getName());
+                    if (!moduleField.getDependency().isMandatory()) {
+                        result.append(format("if(%s != null) {\n", moduleField.getName()));
+                    }
+                    result.append(format("dependencyResolver.validateDependency(%s.class, %s, %sJmxAttribute);\n",
+                            moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName(),
+                            moduleField.getName()));
+                    if (!moduleField.getDependency().isMandatory()) {
+                        result.append("}\n");
+                    }
                 }
             }
         }
-        result += "\n"+
-                "customValidation();\n"+
-            "}\n"+
-            "\n"+
-            "protected void customValidation() {\n"+
-            "}\n";
-        return result;
+        result.append("\n" +
+                "customValidation();\n" +
+                "}\n" +
+                "\n" +
+                "protected void customValidation() {\n" +
+                "}\n");
+        return result.toString();
     }
 
-    private static String getLogger(FullyQualifiedName fqn) {
-        return format("private static final %s logger = %s.getLogger(%s.class);",
+    private static String getLoggerDefinition(FullyQualifiedName fqn) {
+        return format("private static final %s LOG = %s.getLogger(%s.class);",
                 Logger.class.getCanonicalName(), LoggerFactory.class.getCanonicalName(), fqn);
     }
 
@@ -386,14 +376,9 @@ public class AbsModuleGeneratedObjectFactory {
     private static String getConstructorStart(FullyQualifiedName fqn,
                                               LinkedHashMap<String, String> parameters, String after) {
         String paramString = Joiner.on(",").withKeyValueSeparator(" ").join(parameters);
-        String setters = "";
-        for (String paramName : parameters.values()) {
-            setters += format("this.%s = %1$s;\n", paramName);
-        }
         return format("public %s(", fqn.getTypeName()) +
                 paramString +
                 ") {\n" +
-                setters +
                 after +
                 "}\n";
     }
@@ -402,10 +387,8 @@ public class AbsModuleGeneratedObjectFactory {
         LinkedHashMap<String, String> parameters = new LinkedHashMap<>();
         parameters.put(ModuleIdentifier.class.getCanonicalName(), "identifier");
         parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
-
-        String setToNulls = "this.oldInstance=null;\n" +
-                "this.oldModule=null;\n";
-        return getConstructorStart(abstractFQN, parameters, setToNulls);
+        String init = "super(identifier, dependencyResolver);\n";
+        return getConstructorStart(abstractFQN, parameters, init);
     }
 
     private static String getCopyFromOldConstructor(FullyQualifiedName abstractFQN) {
@@ -414,6 +397,11 @@ public class AbsModuleGeneratedObjectFactory {
         parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
         parameters.put(abstractFQN.getTypeName(), "oldModule");
         parameters.put(AutoCloseable.class.getCanonicalName(), "oldInstance");
-        return getConstructorStart(abstractFQN, parameters, "");
+        String init = "super(identifier, dependencyResolver, oldModule, oldInstance);\n";
+        return getConstructorStart(abstractFQN, parameters, init);
+    }
+
+    public String getGetLogger() {
+        return new MethodDefinition(Logger.class.getCanonicalName(), "getLogger", Collections.<Field>emptyList(), "return LOG;").toString();
     }
 }