X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fconfig%2Fyang-jmx-generator-plugin%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fconfig%2Fyangjmxgenerator%2Fplugin%2Fgofactory%2FAbsModuleGeneratedObjectFactory.java;fp=opendaylight%2Fconfig%2Fyang-jmx-generator-plugin%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fconfig%2Fyangjmxgenerator%2Fplugin%2Fgofactory%2FAbsModuleGeneratedObjectFactory.java;h=aa06cb97d74eafcc35eeea7f16128e7f94743cfb;hp=0000000000000000000000000000000000000000;hb=d5d9d1a9b29fdfb93b78f102ab5463e773453651;hpb=9c9f6e506395f806978a955a8cf51ba736b978ad diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.java new file mode 100644 index 0000000000..aa06cb97d7 --- /dev/null +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.java @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.yangjmxgenerator.plugin.gofactory; + +import static java.lang.String.format; + +import com.google.common.base.Joiner; +import com.google.common.base.Optional; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.annotations.Description; +import org.opendaylight.controller.config.api.runtime.RootRuntimeBeanRegistrator; +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.IdentityRefModuleField; +import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Method; +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; +import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObjectBuilder; +import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder; +import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.TypeName; +import org.opendaylight.yangtools.yang.common.QName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AbsModuleGeneratedObjectFactory { + + public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional copyright) { + FullyQualifiedName abstractFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractModuleName()); + Optional classJavaDoc = Optional.fromNullable(mbe.getNullableDescription()); + AbstractModuleTemplate abstractModuleTemplate = TemplateFactory.abstractModuleTemplateFromMbe(mbe); + Optional header = abstractModuleTemplate.getHeaderString(); + + List implementedInterfaces = new ArrayList<>(); + for(String implemented: abstractModuleTemplate.getTypeDeclaration().getImplemented()) { + implementedInterfaces.add(FullyQualifiedName.fromString(implemented)); + } + Optional maybeRegistratorType; + if (abstractModuleTemplate.isRuntime()) { + maybeRegistratorType = Optional.of(FullyQualifiedName.fromString(abstractModuleTemplate.getRegistratorType())); + } else { + maybeRegistratorType = Optional.absent(); + } + + return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, implementedInterfaces, + abstractModuleTemplate.getModuleFields(), maybeRegistratorType, abstractModuleTemplate.getMethods(), + mbe.getYangModuleQName()); + } + + public GeneratedObject toGeneratedObject(FullyQualifiedName abstractFQN, + Optional copyright, + Optional header, + Optional classJavaDoc, + List implementedInterfaces, + List moduleFields, + Optional maybeRegistratorType, + List methods, + QName yangModuleQName) { + JavaFileInputBuilder b = new JavaFileInputBuilder(); + + Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName); + b.addClassAnnotation(moduleQNameAnnotation); + + b.setFqn(abstractFQN); + b.setTypeName(TypeName.absClassType); + + b.setCopyright(copyright); + b.setHeader(header); + b.setClassJavaDoc(classJavaDoc); + for(FullyQualifiedName implemented: implementedInterfaces) { + b.addImplementsFQN(implemented); + } + if (classJavaDoc.isPresent()) { + b.addClassAnnotation(format("@%s(value=\"%s\")", Description.class.getCanonicalName(), classJavaDoc.get())); + } + + // add logger: + b.addToBody(getLogger(abstractFQN)); + + b.addToBody("//attributes start"); + for(ModuleField moduleField: moduleFields) { + b.addToBody(moduleField.toString() +"\n"); + } + + b.addToBody("//attributes end"); + + + b.addToBody(getCommonFields(abstractFQN)); + + + b.addToBody(getNewConstructor(abstractFQN)); + b.addToBody(getCopyFromOldConstructor(abstractFQN)); + + b.addToBody(getRuntimeRegistratorCode(maybeRegistratorType)); + b.addToBody(getValidationMethods(moduleFields)); + + b.addToBody(getCachesOfResolvedDependencies(moduleFields)); + b.addToBody(getCachesOfResolvedIdentityRefs(moduleFields)); + b.addToBody(getGetInstance(moduleFields)); + b.addToBody(getReuseLogic(moduleFields, abstractFQN)); + b.addToBody(getEqualsAndHashCode(abstractFQN)); + + b.addToBody(getMethods(methods)); + + return new GeneratedObjectBuilder(b.build()).toGeneratedObject(); + } + + private static String getMethods(List methods) { + String result = "\n// getters and setters\n"; + for(Method method: methods) { + result += method.toString()+"\n"; + } + return result; + } + + 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"+ + format("%s that = (%1$s) o;\n", abstractFQN.getTypeName())+ + "return identifier.equals(that.identifier);\n"+ + "}\n"+ + "\n"+ + "@Override\n"+ + "public int hashCode() {\n"+ + "return identifier.hashCode();\n"+ + "}\n"; + } + + private static String getReuseLogic(List 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"; + // 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 + + for (ModuleField moduleField : moduleFields) { + 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()); + } 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 += "\n"+ + "return true;\n"+ + "}\n"; + + return result; + } + + private static String getGetInstance(List moduleFields) { + String result = "\n"+ + "@Override\n"+ + format("public final %s getInstance() {\n", AutoCloseable.class.getCanonicalName())+ + "if(instance==null) {\n"; + // create instance start + + // loop through dependent fields, use dependency resolver to instantiate dependencies. Do it in loop in case field represents list of dependencies. + Map resolveDependenciesMap = new HashMap<>(); + for(ModuleField moduleField: moduleFields) { + if (moduleField.isDependent()) { + String str; + 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); + } else { + str = format( + "%1$sDependency = dependencyResolver.resolveInstance(%2$s.class, %1$s, %1$sJmxAttribute);", + moduleField.getName(), osgi); + } + resolveDependenciesMap.put(moduleField, str); + } + } + + // wrap each field resolvation statement with if !=null when dependency is not mandatory + for (Map.Entry entry : resolveDependenciesMap.entrySet()) { + if (entry.getKey().getDependency().isMandatory() == false) { + result += format("if (%s!=null) {\n%s;\n}", entry.getKey().getName(), entry.getValue()); + } else { + result += 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()); + if (moduleField.isList()) { + result += 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 += "}\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));", + moduleField.getAttributeName(), moduleField.getName(), + ((IdentityRefModuleField)moduleField).getIdentityBaseClass()); + result += "}\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("private 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"; + } + + private static String getCachesOfResolvedIdentityRefs(List moduleFields) { + StringBuilder result = new StringBuilder(); + for (ModuleField moduleField : moduleFields) { + if (moduleField.isIdentityRef()) { + IdentityRefModuleField field = (IdentityRefModuleField) moduleField; + result.append(format("private %s %s;\n", field.getIdentityClassType(), field.getIdentityClassName())); + } + } + return result.toString(); + } + + private static String getCachesOfResolvedDependencies(List moduleFields) { + StringBuilder result = new StringBuilder(); + for (ModuleField moduleField: moduleFields) { + if (moduleField.isDependent()) { + String osgi = moduleField.getDependency().getSie().getExportedOsgiClassName(); + if (moduleField.isList()) { + result + .append(format("private java.util.List<%s> %sDependency = new java.util.ArrayList<%s>();", osgi, moduleField.getName(), osgi)) + .append(format("protected final java.util.List<%s> get%sDependency(){\n", osgi, moduleField.getAttributeName())) + .append(format("return %sDependency;\n", moduleField.getName())) + .append("}\n"); + } else { + result.append(format( + "private %s %sDependency;\n"+ + "protected final %s get%sDependency(){\n"+ + "return %sDependency;\n"+ + "}", + osgi, moduleField.getName(), osgi, moduleField.getAttributeName(), moduleField.getName())); + } + } + } + return result.toString(); + } + + private static String getRuntimeRegistratorCode(Optional maybeRegistratorType) { + if (maybeRegistratorType.isPresent()) { + String registratorType = maybeRegistratorType.get().toString(); + + return "\n"+ + format("private %s rootRuntimeBeanRegistratorWrapper;\n", registratorType)+ + "\n"+ + format("public %s getRootRuntimeBeanRegistratorWrapper(){\n", registratorType)+ + "return rootRuntimeBeanRegistratorWrapper;\n"+ + "}\n"+ + "\n"+ + "@Override\n"+ + format("public void setRuntimeBeanRegistrator(%s rootRuntimeRegistrator){\n", RootRuntimeBeanRegistrator.class.getCanonicalName())+ + format("this.rootRuntimeBeanRegistratorWrapper = new %s(rootRuntimeRegistrator);\n", registratorType)+ + "}\n"; + } else { + return ""; + } + } + + private static String getValidationMethods(List moduleFields) { + String result = "\n"+ + "@Override\n"+ + "public void validate() {\n"; + // validate each mandatory dependency + for(ModuleField moduleField: moduleFields) { + if (moduleField.isDependent() && moduleField.getDependency().isMandatory()) { + 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"; + } else { + result += format("dependencyResolver.validateDependency(%s.class, %s, %sJmxAttribute);", + moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName(), moduleField.getName()); + } + } + } + result += "\n"+ + "customValidation();\n"+ + "}\n"+ + "\n"+ + "protected void customValidation() {\n"+ + "}\n"; + return result; + } + + private static String getLogger(FullyQualifiedName fqn) { + return format("private static final %s logger = %s.getLogger(%s.class);", + Logger.class.getCanonicalName(), LoggerFactory.class.getCanonicalName(), fqn); + } + + // assumes that each parameter name corresponds to an field in this class, constructs lines setting this.field = field; + private static String getConstructorStart(FullyQualifiedName fqn, + LinkedHashMap 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"; + } + + private static String getNewConstructor(FullyQualifiedName abstractFQN) { + LinkedHashMap 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); + } + + private static String getCopyFromOldConstructor(FullyQualifiedName abstractFQN) { + LinkedHashMap parameters = new LinkedHashMap<>(); + parameters.put(ModuleIdentifier.class.getCanonicalName(), "identifier"); + parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver"); + parameters.put(abstractFQN.getTypeName(), "oldModule"); + parameters.put(AutoCloseable.class.getCanonicalName(), "oldInstance"); + return getConstructorStart(abstractFQN, parameters, ""); + } +}