+++ /dev/null
-/*
- * 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 com.google.common.base.Optional
-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.*
-import org.opendaylight.yangtools.yang.common.QName
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-public class AbsModuleGeneratedObjectFactory {
-
- public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
- FullyQualifiedName abstractFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractModuleName())
- Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription())
- AbstractModuleTemplate abstractModuleTemplate = TemplateFactory.abstractModuleTemplateFromMbe(mbe)
- Optional<String> header = abstractModuleTemplate.headerString;
- List<FullyQualifiedName> implementedInterfaces = abstractModuleTemplate.getTypeDeclaration().getImplemented().collect {
- FullyQualifiedName.fromString(it)
- }
- Optional<FullyQualifiedName> 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.yangModuleQName
- )
- }
-
- public GeneratedObject toGeneratedObject(FullyQualifiedName abstractFQN,
- Optional<String> copyright,
- Optional<String> header,
- Optional<String> classJavaDoc,
- List<FullyQualifiedName> implementedInterfaces,
- List<ModuleField> moduleFields,
- Optional<FullyQualifiedName> maybeRegistratorType,
- List<Method> 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);
- implementedInterfaces.each { b.addImplementsFQN(it) }
- if (classJavaDoc.isPresent()) {
- b.addClassAnnotation("@${Description.canonicalName}(value=\"${classJavaDoc.get()}\")")
- }
-
- // add logger:
- b.addToBody(getLogger(abstractFQN));
-
- b.addToBody("//attributes start");
-
- b.addToBody(moduleFields.collect { it.toString() }.join("\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<Method> methods) {
- String result = """
- // getters and setters
- """
- result += methods.collect{it.toString()}.join("\n")
- return result
- }
-
- private static String getEqualsAndHashCode(FullyQualifiedName abstractFQN) {
- return """
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ${abstractFQN.typeName} that = (${abstractFQN.typeName}) o;
- return identifier.equals(that.identifier);
- }
-
- @Override
- public int hashCode() {
- return identifier.hashCode();
- }
- """
- }
-
- private static String getReuseLogic(List<ModuleField> moduleFields, FullyQualifiedName abstractFQN) {
- String result = """
- public boolean canReuseInstance(${abstractFQN.typeName} oldModule){
- // allow reusing of old instance if no parameters was changed
- return isSame(oldModule);
- }
-
- public ${AutoCloseable.canonicalName} reuseInstance(${AutoCloseable.canonicalName} oldInstance){
- // implement if instance reuse should be supported. Override canReuseInstance to change the criteria.
- return oldInstance;
- }
- """
- // isSame method that detects changed fields
- result += """
- public boolean isSame(${abstractFQN.typeName} other) {
- if (other == null) {
- throw new IllegalArgumentException("Parameter 'other' is null");
- }
- """
- // loop through fields, do deep equals on each field
- result += moduleFields.collect { field ->
- if (field.isListOfDependencies()) {
- return """
- if (${field.name}Dependency.equals(other.${field.name}Dependency) == false) {
- return false;
- }
- for (int idx = 0; idx < ${field.name}Dependency.size(); idx++) {
- if (${field.name}Dependency.get(idx) != other.${field.name}Dependency.get(idx)) {
- return false;
- }
- }
- """
- } else if (field.isDependent()) {
- return """
- if (${field.name}Dependency != other.${field.name}Dependency) { // reference to dependency must be same
- return false;
- }
- """
- } else {
- return """
- if (java.util.Objects.deepEquals(${field.name}, other.${field.name}) == false) {
- return false;
- }
- """
- }
- }.join("\n")
-
-
- result += """
- return true;
- }
- """
-
- return result
- }
-
- private static String getGetInstance(List<ModuleField> moduleFields) {
- String result = """
- @Override
- public final ${AutoCloseable.canonicalName} getInstance() {
- if(instance==null) {
- """
- // 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<ModuleField, String> resolveDependenciesMap = moduleFields.findAll {
- it.isDependent()
- }.collectEntries { ModuleField field ->
- [field, field.isList() ?
- """
- ${field.name}Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
- for(javax.management.ObjectName dep : ${field.name}) {
- ${field.name}Dependency.add(dependencyResolver.resolveInstance(${
- field.dependency.sie.exportedOsgiClassName
- }.class, dep, ${field.name}JmxAttribute));
- }
- """
- :
- """
- ${field.name}Dependency = dependencyResolver.resolveInstance(${
- field.dependency.sie.exportedOsgiClassName
- }.class, ${field.name}, ${field.name}JmxAttribute);
- """
- ]
- }
- // wrap each field resolvation statement with if !=null when dependency is not mandatory
- def wrapWithNullCheckClosure = {Map<ModuleField, String> map, predicate -> map.collect { ModuleField key, String value ->
- predicate(key) ? """
- if(${key.name}!=null) {
- ${value}
- }
- """ : value
- }.join("\n")
- }
-
- result += wrapWithNullCheckClosure(resolveDependenciesMap, {ModuleField key ->
- key.getDependency().isMandatory() == false} )
-
- // add code to inject dependency resolver to fields that support it
- Map<ModuleField, String> injectDepsMap = moduleFields.findAll { it.needsDepResolver }.collectEntries { field ->
- if (field.isList()) {
- return [field,"""
- for(${field.genericInnerType} candidate : ${field.name}) {
- candidate.injectDependencyResolver(dependencyResolver);
- }
- """]
- } else {
- return [field, "${field.name}.injectDependencyResolver(dependencyResolver);"]
- }
- }
-
- result += wrapWithNullCheckClosure(injectDepsMap, {true})
-
- // identity refs need to be injected with dependencyResolver and base class
- Map<ModuleField, String> resolveIdentityMap = moduleFields.findAll { it.isIdentityRef() }.collectEntries { IdentityRefModuleField field ->
- [field,
- "set${field.attributeName}(${field.name}.resolveIdentity(dependencyResolver, ${field.identityBaseClass}.class));"]
- }
-
- result += wrapWithNullCheckClosure(resolveIdentityMap, {true})
-
- // create instance end: reuse and recreate logic
- result += """
- if(oldInstance!=null && canReuseInstance(oldModule)) {
- instance = reuseInstance(oldInstance);
- } else {
- if(oldInstance!=null) {
- try {
- oldInstance.close();
- } catch(Exception e) {
- logger.error("An error occurred while closing old instance " + oldInstance, e);
- }
- }
- instance = createInstance();
- if (instance == null) {
- throw new IllegalStateException("Error in createInstance - null is not allowed as return value");
- }
- }
- }
- return instance;
- }
- public abstract ${AutoCloseable.canonicalName} createInstance();
- """
- return result
- }
-
- private static String getCommonFields(FullyQualifiedName abstractFQN) {
- return """
- private final ${abstractFQN.typeName} oldModule;
- private final ${AutoCloseable.canonicalName} oldInstance;
- private ${AutoCloseable.canonicalName} instance;
- private final ${DependencyResolver.canonicalName} dependencyResolver;
- private final ${ModuleIdentifier.canonicalName} identifier;
- @Override
- public ${ModuleIdentifier.canonicalName} getIdentifier() {
- return identifier;
- }
- """
- }
-
- private static String getCachesOfResolvedIdentityRefs(List<ModuleField> moduleFields) {
- return moduleFields.findAll { it.isIdentityRef() }.collect { IdentityRefModuleField field ->
- "private ${field.identityClassType} ${field.identityClassName};"
- }.join("\n")
- }
-
- private static String getCachesOfResolvedDependencies(List<ModuleField> moduleFields) {
- return moduleFields.findAll { it.dependent }.collect { field ->
- if (field.isList()) {
- return """
- private java.util.List<${field.dependency.sie.exportedOsgiClassName}> ${
- field.name
- }Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
- protected final java.util.List<${field.dependency.sie.exportedOsgiClassName}> get${
- field.attributeName
- }Dependency(){
- return ${field.name}Dependency;
- }
- """
- } else {
- return """
- private ${field.dependency.sie.exportedOsgiClassName} ${field.name}Dependency;
- protected final ${field.dependency.sie.exportedOsgiClassName} get${field.attributeName}Dependency(){
- return ${field.name}Dependency;
- }
- """
- }
- }.join("\n")
- }
-
- private static String getRuntimeRegistratorCode(Optional<FullyQualifiedName> maybeRegistratorType) {
- if (maybeRegistratorType.isPresent()) {
- String registratorType = maybeRegistratorType.get()
-
- return """
- private ${registratorType} rootRuntimeBeanRegistratorWrapper;
-
- public ${registratorType} getRootRuntimeBeanRegistratorWrapper(){
- return rootRuntimeBeanRegistratorWrapper;
- }
-
- @Override
- public void setRuntimeBeanRegistrator(${RootRuntimeBeanRegistrator.canonicalName} rootRuntimeRegistrator){
- this.rootRuntimeBeanRegistratorWrapper = new ${registratorType}(rootRuntimeRegistrator);
- }
- """
- } else {
- return ""
- }
- }
-
- private static String getValidationMethods(List<ModuleField> moduleFields) {
- String result = """
- @Override
- public void validate() {
- """
- // validate each mandatory dependency
- List<String> lines = moduleFields.findAll{(it.dependent && it.dependency.mandatory)}.collect { field ->
- if (field.isList()) {
- return "" +
- "for(javax.management.ObjectName dep : ${field.name}) {\n" +
- " dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, dep, ${field.name}JmxAttribute);\n" +
- "}\n"
- } else {
- return "dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, ${field.name}, ${field.name}JmxAttribute);"
- }
- }
- result += lines.findAll { it.isEmpty() == false }.join("\n")
- result += """
- customValidation();
- }
-
- protected void customValidation(){
- }
- """
- return result
- }
-
- private static String getLogger(FullyQualifiedName fqn) {
- return "private static final ${Logger.canonicalName} logger = ${LoggerFactory.canonicalName}.getLogger(${fqn.toString()}.class);"
- }
-
- // 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<String, String> parameters, String after) {
- return "public ${fqn.typeName}(" +
- parameters.collect { it.key + " " + it.value }.join(",") +
- ") {\n" +
- parameters.values().collect { "this.${it}=${it};\n" }.join() +
- after +
- "}\n"
- }
-
- private static String getNewConstructor(FullyQualifiedName abstractFQN) {
- LinkedHashMap<String, String> parameters = [
- (ModuleIdentifier.canonicalName): "identifier",
- (DependencyResolver.canonicalName): "dependencyResolver"
- ]
- String setToNulls = ["oldInstance", "oldModule"].collect { "this.${it}=null;\n" }.join()
- return getConstructorStart(abstractFQN, parameters, setToNulls)
- }
-
- private static String getCopyFromOldConstructor(FullyQualifiedName abstractFQN) {
- LinkedHashMap<String, String> parameters = [
- (ModuleIdentifier.canonicalName): "identifier",
- (DependencyResolver.canonicalName): "dependencyResolver",
- (abstractFQN.typeName): "oldModule",
- (AutoCloseable.canonicalName): "oldInstance"
- ]
- return getConstructorStart(abstractFQN, parameters, "")
- }
-}