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

com.devonfw.cobigen.impl.extension.ClassServiceLoader Maven / Gradle / Ivy

There is a newer version: 2021.12.006
Show newest version
package com.devonfw.cobigen.impl.extension;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.devonfw.cobigen.api.extension.GeneratorPluginActivator;
import com.devonfw.cobigen.api.extension.TextTemplateEngine;

/**
 * This class is is the manual implementation of a Lazy {@link ServiceLoader} allowing introspection without
 * instantiating a plug-in. Introspection get's supported by JDK 9 earliest by the ServiceLoader implementation of JDK.
 * This class can be treated as a workaround for JDK 8 and can be removed as soon as we raise the lower limit of JDK
 * support to at least JDK 9.
 */
public class ClassServiceLoader {

  /** Logger instance. */
  private static final Logger LOG = LoggerFactory.getLogger(ClassServiceLoader.class);

  /** Classes detected as GeneratorPluginActivators */
  private static Set> generatorPluginActivatorClasses = new HashSet<>();

  /** Classes detected as TemplateEngines */
  private static Set> templateEngineClasses = new HashSet<>();

  static {
    LOG.debug("Initiating CobiGen");
    lookupServices(Thread.currentThread().getContextClassLoader());
  }

  /**
   * Detects CobiGen extensions on the classpath of the given class loader
   *
   * @param classLoader determining the classpath to look at
   */
  public static void lookupServices(ClassLoader classLoader) {

    LOG.info("Searching for plug-ins at classloader {}", classLoader);
    if (LOG.isDebugEnabled()) {
      if (classLoader instanceof URLClassLoader) {
        LOG.debug("URL Classloader with URLs:");
        Arrays.stream(((URLClassLoader) classLoader).getURLs()).forEach(url -> LOG.debug("  * {}", url));
      }
    }
    generatorPluginActivatorClasses.clear();
    templateEngineClasses.clear();
    LOG.info("Loading plug-in activators...");
    lookupServices(GeneratorPluginActivator.class, generatorPluginActivatorClasses, classLoader);
    LOG.info("Loading template engines...");
    lookupServices(TextTemplateEngine.class, templateEngineClasses, classLoader);
  }

  /**
   * Detects services of extensions type and adds them to the clazzSet
   *
   * @param  the extension type to be found by {@link ServiceLoader} mechanism
   * @param extensionType the extension type
   * @param clazzSet the set to add the detected classes
   * @param contextClassLoader the classloader to be used for classpath scanning
   */
  @SuppressWarnings("unchecked")
  private static  void lookupServices(Class extensionType, Set> clazzSet,
      ClassLoader contextClassLoader) {

    try {
      Enumeration foundGeneratorPluginActivators = contextClassLoader
          .getResources("META-INF/services/" + extensionType.getName());

      while (foundGeneratorPluginActivators.hasMoreElements()) {
        URL url = foundGeneratorPluginActivators.nextElement();
        LOG.debug("Found classpath entry: {}", url);
        String activatorClassName = null;
        try {
          URLConnection con = url.openConnection();
          try (InputStream in = con.getInputStream()) {
            List lines = IOUtils.readLines(in, StandardCharsets.UTF_8);
            LOG.debug("Lines of service loader file: {}", lines);
            if (!lines.isEmpty()) {
              activatorClassName = lines.get(0);
              Class loadClass = contextClassLoader.loadClass(activatorClassName);
              if (extensionType.isAssignableFrom(loadClass)) {
                LOG.info("Found {} {}", extensionType.getSimpleName(), activatorClassName);
                clazzSet.add((Class) loadClass);
              } else {
                LOG.warn("ServiceLoader extension with class {} is not a subclass of {}. Skipping...",
                    activatorClassName, extensionType.getCanonicalName());
              }
            }
          }
        } catch (IOException e) {
          LOG.error("Could not read plug-in at {}", url, LOG.isDebugEnabled() ? e : null);
        } catch (ClassNotFoundException e) {
          LOG.error("Could not load plug-in with class {}", activatorClassName, LOG.isDebugEnabled() ? e : null);
        }
      }
      if (clazzSet.isEmpty()) {
        LOG.error("At least one plug-in should be registered of type {}", extensionType.getSimpleName());
      }
    } catch (Throwable e1) {
      LOG.error("Unable to retrieve {} by ServiceLoader interface", extensionType, e1);
    }
  }

  /**
   * @return the detected classes of {@link GeneratorPluginActivator}
   */
  public static Set> getGeneratorPluginActivatorClasses() {

    return generatorPluginActivatorClasses;
  }

  /**
   * @return the detected classes of {@link TextTemplateEngine}
   */
  public static Set> getTemplateEngineClasses() {

    return templateEngineClasses;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy