All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.appops.maven.plugin.mojo.ConfigGeneratorMojo Maven / Gradle / Ivy


package org.appops.maven.plugin.mojo;

import com.google.common.collect.Table;
/*
 * AppOps is a Java framework to develop, deploy microservices with ease and is available for free
 * and common use developed by AinoSoft ( www.ainosoft.com )
 *
 * AppOps and AinoSoft are registered trademarks of Aino Softwares private limited, India.
 *
 * Copyright (C) <2016> 
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version along with applicable additional terms as
 * provisioned by GPL 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License and applicable additional terms
 * along with this program.
 *
 * If not, see  and 
 */
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URLClassLoader;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.appops.configuration.guice.ConfigServiceModule;
import org.appops.configuration.slimimpl.SlimImplConfigTable;
import org.appops.configuration.slimimpl.SlimImplIdentifier;
import org.appops.configuration.slimimpl.SlimImplStructure;
import org.appops.core.ClassPathAnalyser;
import org.appops.core.TypeScanner;
import org.appops.core.annotation.Config;
import org.appops.core.annotation.CoreConfig;
import org.appops.core.annotation.Slim;
import org.appops.core.constant.ConfigType;
import org.appops.core.deployment.ServiceConfiguration;
import org.appops.core.service.annotation.Service;
import org.appops.marshaller.DescriptorType;
import org.appops.marshaller.Marshaller;
import org.appops.marshaller.guice.MarshallerModule;
import org.appops.maven.plugin.helper.MojoHelper;

/**
 * Appops maven plugin which generate appops service configuration using configuration parameters
 * provided.
 */
@Mojo(name = "gen-config", requiresDependencyResolution = ResolutionScope.RUNTIME)
public class ConfigGeneratorMojo extends AbstractMojo {

  @Parameter(required = true, alias = "profileRoot")
  private String profileRoot = "env-config/";
  @Parameter(defaultValue = "${project}", required = true)
  private MavenProject project;
  @Parameter(required = true)
  private String serviceAnnotation;

  private Injector injector;
  private Marshaller marshaller;
  private ClassPathAnalyser classPathAnalyser;
  private URLClassLoader classLoader;

  /**
   * Default constructor.
   */
  public ConfigGeneratorMojo() {
    injector = createGuiceInjector();
    marshaller = injector.getInstance(Marshaller.class);
    if (!profileRoot.endsWith(File.separator)) {
      profileRoot += File.separator;
    }
  }

  @Override
  public void execute() throws MojoExecutionException, MojoFailureException {
    try {
      classLoader = new MojoHelper().getClassLoader(project);
      Thread.currentThread().setContextClassLoader(classLoader);
      classPathAnalyser = new ClassPathAnalyser(classLoader);
      classPathAnalyser.setTypeScanner(new TypeScanner());

      Set> configClasses = classPathAnalyser.getAnnotatedTypes(Config.class);
      SlimImplConfigTable table = new SlimImplConfigTable();
      for (Class clazz : configClasses) {
        if (!clazz.isAnnotation()) {
          SlimImplIdentifier slimImplConfig = analyzeAnnotations(clazz.getAnnotations());
          String configJson = marshaller.marshall(clazz.newInstance(), DescriptorType.YML);

          table.addConfiguration(slimImplConfig.getServiceName(), slimImplConfig.getConfigType(),
              clazz.getCanonicalName(), configJson);
        }
      }

      populateModuleConfig(classPathAnalyser, table);
      generateConfig(table);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Populate modules configuration into {@link SlimImplConfigTable}.
   * 
   * @param classPathAnalyser Performs java reflection based classpath analysis. It provides
   *        functionalities such as find-classes-from-annotation, find-class-methods etc.
   * @param table configuration table to populate values.
   */
  private void populateModuleConfig(ClassPathAnalyser classPathAnalyser,
      SlimImplConfigTable table) {
    Map>> slimModules =
        classPathAnalyser.getSlimModuleAnnotatedTypeMap();
    for (String serviceName : slimModules.keySet()) {
      table.addSlimModules(serviceName, slimModules.get(serviceName));
    }
    populateImplModules(classPathAnalyser, table);
  }

  /**
   * Populate impl modules into {@link SlimImplConfigTable}.
   * 
   * @param classPathAnalyser Performs java reflection based classpath analysis. It provides
   *        functionalities such as find-classes-from-annotation, find-class-methods etc.
   * @param table configuration table to populate values.
   */
  private void populateImplModules(ClassPathAnalyser classPathAnalyser, SlimImplConfigTable table) {
    Map>> slimModules =
        classPathAnalyser.getImplModuleAnnotatedTypeMap();
    for (String serviceName : slimModules.keySet()) {
      table.addImplModules(serviceName, slimModules.get(serviceName));
    }
  }

  /**
   * Generate configuration as per {@link SlimImplConfigTable}.
   * 
   * @param table configuration table to generate files.
   * @throws Exception throws if occurred in between process
   */
  private void generateConfig(SlimImplConfigTable table) throws Exception {
    createCoreConfig();

    Table configTable = table.getConfigTable();
    Map> map = configTable.rowMap();

    for (String servicename : map.keySet()) {
      Map configMap = map.get(servicename);
      for (ConfigType configType : configMap.keySet()) {
        String folderName = servicename.substring(servicename.lastIndexOf(".") + 1);
        String data = marshaller.marshall(configMap.get(configType).setAnnotationClass(servicename),
            DescriptorType.YML);
        FileUtils.writeStringToFile(
            new File(profileRoot + folderName + "/" + configType.name().toLowerCase() + ".yml"),
            data, Charset.defaultCharset());
      }
    }
  }

  /**
   * Create core {@link ServiceConfiguration} configuration.
   * 
   * @throws IOException throws an exception if file operation fails.
   */
  private void createCoreConfig() throws Exception {
    ServiceConfiguration configuration = injector.getInstance(ServiceConfiguration.class);
    configuration
        .setAnnotationClass((Class) classLoader.loadClass(serviceAnnotation));
    String serviceName = serviceAnnotation.substring(serviceAnnotation.lastIndexOf(".") + 1);
    configuration.setServiceName(serviceName);
    populateCoreConfig(configuration);

    String coreConfig = marshaller.marshall(configuration, DescriptorType.YML);
    FileUtils.writeStringToFile(new File(profileRoot + "core.yml"), coreConfig,
        Charset.defaultCharset());
  }

  /**
   * Populate {@link ServiceConfiguration} object.
   * 
   * @param configuration object of {@link ServiceConfiguration} to be populate.
   * @throws Exception throws an exception if class instaniation fails.
   */
  private void populateCoreConfig(ServiceConfiguration configuration) throws Exception {
    Set> coreConfigMap = classPathAnalyser.getAnnotatedTypes(CoreConfig.class);
    for (Class clazz : coreConfigMap) {
      configuration.addConfig(clazz.getCanonicalName(), clazz.newInstance());
    }
  }

  /**
   * Analyze the service name and whether it is slim class or impl class and populate into
   * {@link SlimImplIdentifier}.
   * 
   * @param annotations annotations present on the config class.
   * @return object of {@link SlimImplIdentifier}.
   */
  private SlimImplIdentifier analyzeAnnotations(Annotation[] annotations) {
    String serviceName = null;
    SlimImplIdentifier slimImplConfig = new SlimImplIdentifier();
    for (Annotation annotation : annotations) {
      if (annotation.annotationType().getName().equals(Slim.class.getTypeName())) {
        slimImplConfig.setConfigType(ConfigType.SLIM);
        continue;
        // slim
      }
      Annotation[] onTopAnnotation = annotation.annotationType().getAnnotations();
      serviceName = getServiceName(onTopAnnotation);
      if (serviceName != null) {
        break;
      }
    }
    slimImplConfig.setServiceName(serviceName);
    return slimImplConfig;
  }

  /**
   * Find service name from annotation list by cheking is the {@link Service} present on annotation
   * or not.
   * 
   * @param onTopAnnotation annotation list from which service name to be find.
   * @return string service name .
   */
  private String getServiceName(Annotation[] onTopAnnotation) {
    String serviceName = null;
    for (Annotation annotation : onTopAnnotation) {
      if (annotation.annotationType().isAnnotationPresent(Service.class)) {
        serviceName = annotation.annotationType().getName();
        break;
      }
    }
    return serviceName;
  }

  /**
   * Creates guice injector required for the goal.
   */
  private Injector createGuiceInjector() {
    return Guice.createInjector(new ConfigServiceModule(), new MarshallerModule());
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy