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

io.ebeaninternal.server.core.bootup.BootupClasses Maven / Gradle / Ivy

There is a newer version: 15.6.0
Show newest version
package io.ebeaninternal.server.core.bootup;

import io.ebean.annotation.DocStore;
import io.ebean.config.IdGenerator;
import io.ebean.config.ScalarTypeConverter;
import io.ebean.config.ServerConfig;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
import io.ebean.event.BeanPostConstructListener;
import io.ebean.event.BeanPostLoad;
import io.ebean.event.BeanQueryAdapter;
import io.ebean.event.ServerConfigStartup;
import io.ebean.event.changelog.ChangeLogListener;
import io.ebean.event.changelog.ChangeLogPrepare;
import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.server.type.ScalarType;
import org.avaje.classpath.scanner.ClassFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.AttributeConverter;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

/**
 * Interesting classes for a EbeanServer such as Embeddable, Entity,
 * ScalarTypes, Finders, Listeners and Controllers.
 */
public class BootupClasses implements ClassFilter {

  private static final Logger logger = LoggerFactory.getLogger(BootupClasses.class);

  private final List> embeddableList = new ArrayList<>();

  private final List> entityList = new ArrayList<>();

  private final List>> scalarTypeList = new ArrayList<>();

  private final List>> scalarConverterList = new ArrayList<>();

  private final List>> attributeConverterList = new ArrayList<>();

  // The following objects are instantiated on first request
  // there is always a candidate list, that holds the class and an
  // instance list, that holds the instance. Once a class is instantiated
  // (or added) it will get removed from the candidate list
  private final List> idGeneratorCandidates = new ArrayList<>();

  private final List> beanPersistControllerCandidates = new ArrayList<>();

  private final List> beanPostLoadCandidates = new ArrayList<>();

  private final List> beanPostConstructListenerCandidates = new ArrayList<>();

  private final List> beanFindControllerCandidates = new ArrayList<>();

  private final List> beanPersistListenerCandidates = new ArrayList<>();

  private final List> beanQueryAdapterCandidates = new ArrayList<>();

  private final List> serverConfigStartupCandidates = new ArrayList<>();

  private final List idGeneratorInstances = new ArrayList<>();
  private final List beanPersistControllerInstances = new ArrayList<>();
  private final List beanPostLoadInstances = new ArrayList<>();
  private final List beanPostConstructListenerInstances = new ArrayList<>();
  private final List beanFindControllerInstances = new ArrayList<>();
  private final List beanPersistListenerInstances = new ArrayList<>();
  private final List beanQueryAdapterInstances = new ArrayList<>();
  private final List serverConfigStartupInstances = new ArrayList<>();

  // single objects
  private Class changeLogPrepareClass;
  private Class changeLogListenerClass;
  private Class changeLogRegisterClass;
  private Class readAuditPrepareClass;
  private Class readAuditLoggerClass;

  private ChangeLogPrepare changeLogPrepare;
  private ChangeLogListener changeLogListener;
  private ChangeLogRegister changeLogRegister;
  private ReadAuditPrepare readAuditPrepare;
  private ReadAuditLogger readAuditLogger;

  public BootupClasses() {
  }

  public BootupClasses(List> list) {
    if (list != null) {
      for (Class cls : list) {
        isMatch(cls);
      }
    }
  }

  /**
   * Run any ServerConfigStartup listeners.
   */
  public void runServerConfigStartup(ServerConfig serverConfig) {

    for (Class cls : serverConfigStartupCandidates) {
      try {
        ServerConfigStartup newInstance = (ServerConfigStartup) cls.newInstance();
        newInstance.onStart(serverConfig);
      } catch (Exception e) {
        // assume that the desired behavior is to fail - add your own try catch if needed
        throw new IllegalStateException("Error running ServerConfigStartup " + cls, e);
      }
    }
    for (ServerConfigStartup startup : serverConfigStartupInstances) {
      try {
        startup.onStart(serverConfig);
      } catch (Exception e) {
        // assume that the desired behavior is to fail - add your own try catch if needed
        throw new IllegalStateException("Error running ServerConfigStartup " + startup.getClass(), e);
      }
    }
  }

  /**
   * Adds the list toAdd to instances and removes any pending
   * candiate, to prevent duplicate instantiiation.
   */
  private  void add(List toAdd, List instances, List> candidates) {
    if (toAdd != null) {
      for (T obj : toAdd) {
        instances.add(obj);
        // don't automatically instantiate
        candidates.remove(obj.getClass());
      }
    }
  }

  /**
   * Add IdGenerator instances (registered explicitly with the ServerConfig).
   */
  public void addIdGenerators(List idGenerators) {
    add(idGenerators, idGeneratorInstances, idGeneratorCandidates);
  }

  /**
   * Add BeanPersistController instances.
   */
  public void addPersistControllers(List beanControllers) {
    add(beanControllers, beanPersistControllerInstances, beanPersistControllerCandidates);
  }

  /**
   * Add BeanPostLoad instances.
   */
  public void addPostLoaders(List postLoaders) {
    add(postLoaders, beanPostLoadInstances, beanPostLoadCandidates);
  }

  /**
   * Add BeanPostConstructListener instances.
   */
  public void addPostConstructListeners(List postConstructListener) {
    add(postConstructListener, beanPostConstructListenerInstances, beanPostConstructListenerCandidates);
  }

  /**
   * Add BeanFindController instances.
   */
  public void addFindControllers(List findControllers) {
    add(findControllers, beanFindControllerInstances, beanFindControllerCandidates);
  }

  public void addPersistListeners(List listenerInstances) {
    add(listenerInstances, beanPersistListenerInstances, beanPersistListenerCandidates);
  }

  public void addQueryAdapters(List queryAdapters) {
    add(queryAdapters, beanQueryAdapterInstances, beanQueryAdapterCandidates);
  }

  public void addServerConfigStartup(List startupInstances) {
    add(startupInstances, serverConfigStartupInstances, serverConfigStartupCandidates);
  }

  public void addChangeLogInstances(ServerConfig serverConfig) {

    readAuditPrepare = serverConfig.getReadAuditPrepare();
    readAuditLogger = serverConfig.getReadAuditLogger();
    changeLogPrepare = serverConfig.getChangeLogPrepare();
    changeLogListener = serverConfig.getChangeLogListener();
    changeLogRegister = serverConfig.getChangeLogRegister();

    // if not already set create the implementations found
    // via classpath scanning
    if (readAuditPrepare == null && readAuditPrepareClass != null) {
      readAuditPrepare = create(readAuditPrepareClass, false);
    }
    if (readAuditLogger == null && readAuditLoggerClass != null) {
      readAuditLogger = create(readAuditLoggerClass, false);
    }
    if (changeLogPrepare == null && changeLogPrepareClass != null) {
      changeLogPrepare = create(changeLogPrepareClass, false);
    }
    if (changeLogListener == null && changeLogListenerClass != null) {
      changeLogListener = create(changeLogListenerClass, false);
    }
    if (changeLogRegister == null && changeLogRegisterClass != null) {
      changeLogRegister = create(changeLogRegisterClass, false);
    }
  }

  /**
   * Create an instance using the default constructor returning null if there
   * is no default constructor (implying the class was not intended to be instantiated
   * automatically via classpath scanning.
   * 

* Use logOnException = true to log the error and carry on. */ private T create(Class cls, boolean logOnException) { try { // instantiate via found class Constructor constructor = cls.getConstructor(); return constructor.newInstance(); } catch (NoSuchMethodException e) { logger.debug("Ignore/expected - no default constructor", e); return null; } catch (Exception e) { if (logOnException) { // not expected but we log and carry on logger.error("Error creating " + cls, e); return null; } else { // ok, stop the bus throw new IllegalStateException("Error creating " + cls, e); } } } /** * Create the instance if it has a default constructor and add it to the list of instances. * It clears the list of classes afterwards, so that each class in the given list is * instantiated only once */ private List createAdd(List instances, List> candidates) { for (Class cls : candidates) { T newInstance = create(cls, true); if (newInstance != null) { instances.add(newInstance); } } candidates.clear(); // important, clear class list! return instances; } public ChangeLogPrepare getChangeLogPrepare() { return changeLogPrepare; } public ChangeLogListener getChangeLogListener() { return changeLogListener; } public ChangeLogRegister getChangeLogRegister() { return changeLogRegister; } public ReadAuditPrepare getReadAuditPrepare() { return readAuditPrepare; } public ReadAuditLogger getReadAuditLogger() { return readAuditLogger; } public List getIdGenerators() { return createAdd(idGeneratorInstances, idGeneratorCandidates); } public List getBeanPersistControllers() { return createAdd(beanPersistControllerInstances, beanPersistControllerCandidates); } public List getBeanPostLoaders() { return createAdd(beanPostLoadInstances, beanPostLoadCandidates); } public List getBeanPostConstructoListeners() { return createAdd(beanPostConstructListenerInstances, beanPostConstructListenerCandidates); } public List getBeanFindControllers() { return createAdd(beanFindControllerInstances, beanFindControllerCandidates); } public List getBeanPersistListeners() { return createAdd(beanPersistListenerInstances, beanPersistListenerCandidates); } public List getBeanQueryAdapters() { return createAdd(beanQueryAdapterInstances, beanQueryAdapterCandidates); } /** * Return the list of Embeddable classes. */ public List> getEmbeddables() { return embeddableList; } /** * Return the list of entity classes. */ public List> getEntities() { return entityList; } /** * Return the list of ScalarTypes found. */ public List>> getScalarTypes() { return scalarTypeList; } /** * Return the list of ScalarConverters found. */ public List>> getScalarConverters() { return scalarConverterList; } /** * Return the list of AttributeConverters found. */ public List>> getAttributeConverters() { return attributeConverterList; } @Override public boolean isMatch(Class cls) { if (isEmbeddable(cls)) { embeddableList.add(cls); } else if (isEntity(cls)) { entityList.add(cls); } else { return isInterestingInterface(cls); } return true; } /** * Look for interesting interfaces. *

* This includes ScalarType, BeanController, BeanFinder and BeanListener. *

*/ @SuppressWarnings("unchecked") private boolean isInterestingInterface(Class cls) { if (Modifier.isAbstract(cls.getModifiers())) { // do not include abstract classes as we can // not instantiate them return false; } boolean interesting = false; // Types if (ScalarType.class.isAssignableFrom(cls)) { scalarTypeList.add((Class>) cls); interesting = true; } if (ScalarTypeConverter.class.isAssignableFrom(cls)) { scalarConverterList.add((Class>) cls); interesting = true; } if (AttributeConverter.class.isAssignableFrom(cls)) { attributeConverterList.add((Class>) cls); interesting = true; } if (IdGenerator.class.isAssignableFrom(cls)) { idGeneratorCandidates.add((Class) cls); interesting = true; } // "Candidates" if (BeanPersistController.class.isAssignableFrom(cls)) { beanPersistControllerCandidates.add((Class) cls); interesting = true; } if (BeanPostLoad.class.isAssignableFrom(cls)) { beanPostLoadCandidates.add((Class) cls); interesting = true; } if (BeanPostConstructListener.class.isAssignableFrom(cls)) { beanPostConstructListenerCandidates.add((Class) cls); interesting = true; } if (BeanFindController.class.isAssignableFrom(cls)) { beanFindControllerCandidates.add((Class) cls); interesting = true; } if (BeanPersistListener.class.isAssignableFrom(cls)) { beanPersistListenerCandidates.add((Class) cls); interesting = true; } if (BeanQueryAdapter.class.isAssignableFrom(cls)) { beanQueryAdapterCandidates.add((Class) cls); interesting = true; } if (ServerConfigStartup.class.isAssignableFrom(cls)) { serverConfigStartupCandidates.add((Class) cls); interesting = true; } // single instances // TODO: What should happen, if there is already an other // changeLogListener assigned? (Last wins? / Exception?) if (ChangeLogListener.class.isAssignableFrom(cls)) { changeLogListenerClass = (Class) cls; interesting = true; } if (ChangeLogRegister.class.isAssignableFrom(cls)) { changeLogRegisterClass = (Class) cls; interesting = true; } if (ChangeLogPrepare.class.isAssignableFrom(cls)) { changeLogPrepareClass = (Class) cls; interesting = true; } if (ReadAuditPrepare.class.isAssignableFrom(cls)) { readAuditPrepareClass = (Class) cls; interesting = true; } if (ReadAuditLogger.class.isAssignableFrom(cls)) { readAuditLoggerClass = (Class) cls; interesting = true; } return interesting; } private boolean isEntity(Class cls) { return has(cls, Entity.class) || has(cls, Table.class) || has(cls, DocStore.class); } private boolean isEmbeddable(Class cls) { return has(cls, Embeddable.class); } /** * Returns true if this class has the annotation (or meta annotation). Does not search recursively. */ private boolean has(Class cls, Class ann) { return AnnotationUtil.findAnnotation(cls, ann) != null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy