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

org.rapidpm.ddi.DI Maven / Gradle / Ivy

There is a newer version: 1.1.1
Show newest version
/*
 * Copyright [2014] [www.rapidpm.org / Sven Ruppert ([email protected])]
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package org.rapidpm.ddi;


import org.rapidpm.ddi.Proxy.ProxyType;
import org.rapidpm.ddi.bootstrap.ClassResolverCheck001;
import org.rapidpm.ddi.implresolver.ImplementingClassResolver;
import org.rapidpm.ddi.producer.InstanceCreator;
import org.rapidpm.ddi.producer.ProducerLocator;
import org.rapidpm.ddi.reflections.ReflectionUtils;
import org.rapidpm.ddi.reflections.ReflectionsModel;
import org.rapidpm.ddi.scopes.InjectionScopeManager;
import org.rapidpm.proxybuilder.ProxyBuilder;
import org.rapidpm.proxybuilder.type.dymamic.DynamicProxyBuilder;
import org.rapidpm.proxybuilder.type.dymamic.virtual.CreationStrategy;
import org.rapidpm.proxybuilder.type.dymamic.virtual.DynamicProxyGenerator;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import static org.rapidpm.ddi.scopes.InjectionScopeManager.listAllActiveScopeNames;


public class DI {

  //  private static final ImplementingClassResolver IMPLEMENTING_CLASS_RESOLVER = new ImplementingClassResolver();
  private static final Set METRICS_ACTIVATED = Collections.synchronizedSet(new HashSet<>());
  private static final Set LOGGING_ACTIVATED = Collections.synchronizedSet(new HashSet<>());
  private static ReflectionsModel reflectionsModel = new ReflectionsModel();
  private static boolean bootstrapedNeeded = true;


  private DI() {
  }

  public static void checkActiveModel() {
    //hole alle Felder die mit einem @Inject versehen sind.
    //pruefe ob es sich um ein Interface handelt
    //pruefe ob es nur einen Producer / eine Implementierung  dazu gibt
    // -- liste Multiplizitäten
    new ClassResolverCheck001().execute();
  }

  public static synchronized void bootstrap() {
//    reflectionsModel = new ReflectionsModel();
    ImplementingClassResolver.clearCache();
    if (bootstrapedNeeded) {
      reflectionsModel.rescann("");
    }
    bootstrapedNeeded = false;
  }

  public static synchronized void clearReflectionModel() {
    reflectionsModel = new ReflectionsModel();
    clearCaches();
    METRICS_ACTIVATED.clear();
    LOGGING_ACTIVATED.clear();
    bootstrapedNeeded = true;
  }

  private static void clearCaches() {
    ImplementingClassResolver.clearCache();
    ProducerLocator.clearCache();
    InjectionScopeManager.cleanUp();
    reflectionsModel.clearCaches();
  }

  public static synchronized void activatePackages(Class clazz) {
    reflectionsModel.rescann(clazz.getPackage().getName());
    clearCaches();
    bootstrapedNeeded = false;
  }

  public static synchronized void activatePackages(String pkg) {
    reflectionsModel.rescann(pkg);
    clearCaches();
    bootstrapedNeeded = false;
  }

  public static synchronized void activatePackages(String pkg, URL... urls) {
    reflectionsModel.rescann(pkg, urls);
    clearCaches();
    bootstrapedNeeded = false;
  }

  public static synchronized void activatePackages(String pkg, Collection urls) {
    reflectionsModel.rescann(pkg, urls);
    clearCaches();
    bootstrapedNeeded = false;
  }

  public static synchronized void activatePackages(boolean parallelExecutors, String pkg) {
    reflectionsModel.setParallelExecutors(parallelExecutors);
    reflectionsModel.rescann(pkg);
    clearCaches();
    bootstrapedNeeded = false;
  }

  public static synchronized void activatePackages(boolean parallelExecutors, String pkg, URL... urls) {
    reflectionsModel.setParallelExecutors(parallelExecutors);
    reflectionsModel.rescann(pkg, urls);
    clearCaches();
    bootstrapedNeeded = false;
  }

  public static synchronized void activatePackages(boolean parallelExecutors, String pkg, Collection urls) {
    reflectionsModel.setParallelExecutors(parallelExecutors);
    reflectionsModel.rescann(pkg, urls);
    clearCaches();
    bootstrapedNeeded = false;
  }

  public static void activateMetrics(String pkgName) {
    final boolean pkgPrefixActivated = reflectionsModel.isPkgPrefixActivated(pkgName);
    if (pkgPrefixActivated) {
      final Collection classesForPkg = reflectionsModel.getClassesForPkg(pkgName);
      METRICS_ACTIVATED.addAll(classesForPkg);
    }
  }

  public static void activateMetrics(Class clazz) {
    final boolean pkgPrefixActivated = reflectionsModel.isPkgPrefixActivated(clazz.getPackage().getName());
    if (pkgPrefixActivated) METRICS_ACTIVATED.add(clazz.getName());
  }

  public static void activateLogging(String pkgName) {
    final boolean pkgPrefixActivated = reflectionsModel.isPkgPrefixActivated(pkgName);
    if (pkgPrefixActivated) {
      final Collection classesForPkg = reflectionsModel.getClassesForPkg(pkgName);
      LOGGING_ACTIVATED.addAll(classesForPkg);
    }
  }

  public static void activateLogging(Class clazz) {
    final boolean pkgPrefixActivated = reflectionsModel.isPkgPrefixActivated(clazz.getPackage().getName());
    if (pkgPrefixActivated) LOGGING_ACTIVATED.add(clazz.getName());
  }

  public static void deActivateMetrics(String pkgName) {
    final Collection classesForPkg = reflectionsModel.getClassesForPkg(pkgName);
    METRICS_ACTIVATED.removeAll(classesForPkg);
  }

  public static void deActivateMetrics(Class clazz) {
    METRICS_ACTIVATED.remove(clazz.getName());
  }

  public static void deActivateLogging(String pkgName) {
    final Collection classesForPkg = reflectionsModel.getClassesForPkg(pkgName);
    LOGGING_ACTIVATED.removeAll(classesForPkg);
  }

  public static void deActivateLogging(Class clazz) {
    LOGGING_ACTIVATED.remove(clazz.getName());
  }

  public static synchronized  T activateDI(T instance) {
    if (bootstrapedNeeded) bootstrap();

    injectAttributes(instance);
    initialize(instance);
    final Class aClass = (Class) instance.getClass();
    final T loggingProxy = createLoggingProxy(aClass, instance);
    final T metricsProxy = createMetricsProxy(aClass, loggingProxy);
    return metricsProxy;
  }

  public static synchronized  T activateDI(Class clazz2Instanciate) {
    if (bootstrapedNeeded) bootstrap();

    final T instance = new InstanceCreator().instantiate(clazz2Instanciate);
    injectAttributes(instance);
    initialize(instance);

    final T loggingProxy = createLoggingProxy(clazz2Instanciate, instance);
    final T metricsProxy = createMetricsProxy(clazz2Instanciate, loggingProxy);
    return metricsProxy;
  }

  public static Set listAllActiveScopes() {
    return listAllActiveScopeNames();
  }

  public static void registerClassForScope(Class clazz, String scope) {
    InjectionScopeManager.registerClassForScope(clazz, scope);
  }

  public static void deRegisterClassForScope(Class clazz) {
    InjectionScopeManager.deRegisterClassForScope(clazz);
  }



  private static  T createMetricsProxy(Class clazz2Instanciate, T instance) {
    if (METRICS_ACTIVATED.contains(clazz2Instanciate.getName())) {
      final Set> staticProxiesFor = getStaticMetricProxiesFor(clazz2Instanciate);
      if (staticProxiesFor.isEmpty()) {
        if (clazz2Instanciate.isInterface()) { //TODO try inMemoryCompile
          return ProxyBuilder.newDynamicProxyBuilder(clazz2Instanciate, instance).addMetrics().build();
        }
      } else if (staticProxiesFor.size() == 1) {
        final Class[] proxyClasses = staticProxiesFor.toArray(new Class[1]);
        return createGeneratedStaticProxy(instance, proxyClasses[0]);
      } else {
        throw new DDIModelException("to many MetricProxies for " + clazz2Instanciate + " -> Proxies are " + staticProxiesFor);
      }
    }
    return instance;
  }


  private static  T createLoggingProxy(Class clazz2Instanciate, T delegator) {
    if (LOGGING_ACTIVATED.contains(clazz2Instanciate.getName())) {
      final Set> staticProxiesFor = getStaticLoggingProxiesFor(clazz2Instanciate);
      if (staticProxiesFor.isEmpty()) {
        if (clazz2Instanciate.isInterface()) { //TODO try inMemoryCompile
          return ProxyBuilder.newDynamicProxyBuilder(clazz2Instanciate, delegator).addLogging().build();
        } else {
          //not interface ??
        }
      } else if (staticProxiesFor.size() == 1) {
        final Class[] proxyClasses = staticProxiesFor.toArray(new Class[1]);
        return createGeneratedStaticProxy(delegator, proxyClasses[0]);
      } else {
        throw new DDIModelException("to many LoggingProxies for " + clazz2Instanciate + " -> Proxies are " + staticProxiesFor);
      }
    }
    return delegator;
  }

  private static  T createGeneratedStaticProxy(final T delegator, final Class staticProxyClass) {
    final T staticProxy = new InstanceCreator().instantiate(staticProxyClass);
    injectAttributes(delegator);
    initialize(delegator);
    new ReflectionUtils().setDelegatorToProxy(staticProxy, delegator);
    return staticProxy;
  }


  private static  void injectAttributes(final T rootInstance) throws SecurityException {
    injectAttributesForClass(rootInstance.getClass(), rootInstance);
  }


  private static  void injectAttributesForClass(Class targetClass, T rootInstance) {
    Class superclass = targetClass.getSuperclass();
    if (superclass != null) {
      injectAttributesForClass(superclass, rootInstance);
    }

    final Field[] fields = targetClass.getDeclaredFields();
    for (final Field field : fields) {
      if (field.isAnnotationPresent(Inject.class)) {

        final Class targetType = field.getType();
        Object value; //Attribute Type for inject

        if (field.isAnnotationPresent(Proxy.class)) {
          value = createProxy(field, targetType);
          DI.activateDI(value);
        } else {
          value = new InstanceCreator().instantiate(targetType);
          DI.activateDI(value);
        }
        if (value != null) {

          injectIntoField(field, rootInstance, value);
        }
      }
    }
  }

  private static Object createProxy(final Field field, final Class targetType) {
    Object value;


    //TODO cross check with activated Metrics.. avoid double Metrics Proxy
    //TODO compare with registered Values for Metrics and Proxies
    final Proxy annotation = field.getAnnotation(Proxy.class);

    final boolean virtual = annotation.virtual();
    final CreationStrategy creationStrategy = annotation.concurrent();
    final boolean metrics = annotation.metrics();
    final boolean secure = annotation.secure(); //woher die Sec Rules?
    final boolean logging = annotation.logging();
    final ProxyType proxyType = annotation.proxyType();
    switch (proxyType) {
      case AUTODETECT:
        break;
      case DYNAMIC:
        break;
      case GENERATED:
        break;
      case STATIC:
        break;
      default:
        break;
    }
    //just now, only dynamic version is created..
    if (virtual) {
      value = DynamicProxyGenerator.newBuilder()
          .withSubject(targetType)
          .withCreationStrategy(CreationStrategy.NO_DUPLICATES)
//                .withServiceFactory(new DDIServiceFactory<>(realClass)) //TODO Test it
          .withServiceFactory(new DDIServiceFactory<>(targetType)) //TODO Test it
          .withCreationStrategy(creationStrategy)
//                .withServiceStrategyFactory(new ServiceStrategyFactoryNotThreadSafe<>())
          .build()
          .make();
    } else {
//            value = new InstanceCreator().instantiate(realClass); // TODO Test it
      value = new InstanceCreator().instantiate(targetType); // TODO Test it //TODO DI.activate
      //activateDI(value); //rekursiver abstieg
    }


    if (metrics || secure || logging) {
      final DynamicProxyBuilder dynamicProxyBuilder = DynamicProxyBuilder.createBuilder(targetType, value);
      if (metrics) {
        dynamicProxyBuilder.addMetrics();
      }
      if (secure) {
//              virtualProxyBuilder.addSecurityRule(()->{});
      }
      if (logging) {
        //virtualProxyBuilder.addLogging();
      }
      value = dynamicProxyBuilder.build();
    }
    return value;
  }


  private static void injectIntoField(final Field field, final Object instance, final Object target) {
    AccessController.doPrivileged((PrivilegedAction) () -> {
      boolean wasAccessible = field.isAccessible();
      field.setAccessible(true);
      try {
        field.set(instance, target);
        return null; // return nothing...
      } catch (IllegalArgumentException | IllegalAccessException ex) {
        throw new IllegalStateException("Cannot set field: " + field, ex);
      } finally {
        field.setAccessible(wasAccessible);
      }
    });
  }

  private static void initialize(Object instance) {
    Class clazz = instance.getClass();
    invokeMethodWithAnnotation(clazz, instance, PostConstruct.class);
  }

  private static void invokeMethodWithAnnotation(Class clazz, final Object instance,
                                                 final Class annotationClass)
      throws IllegalStateException, SecurityException {

    final Set methodsAnnotatedWith = reflectionsModel.getMethodsAnnotatedWith(clazz, new PostConstruct() {
      @Override
      public Class annotationType() {
        return PostConstruct.class;
      }
    });

    methodsAnnotatedWith.forEach(m -> {
      try {
        final boolean accessible = m.isAccessible();
        m.setAccessible(true);
        m.invoke(instance);
        m.setAccessible(accessible);
      } catch (IllegalAccessException | InvocationTargetException e) {
        e.printStackTrace();
      }
    });
  }

  //delegator

  public static Set listAllActivatedMetrics() {
    return Collections.unmodifiableSet(METRICS_ACTIVATED);
  }


  public static  Set> getStaticMetricProxiesFor(final Class type) {
    return reflectionsModel.getStaticMetricProxiesFor(type);
  }

  public static  Set> getStaticLoggingProxiesFor(final Class type) {
    return reflectionsModel.getStaticLoggingProxiesFor(type);
  }

  public static  Class resolveImplementingClass(final Class interf) {
    return ImplementingClassResolver.resolve(interf);
  }

  public static boolean isPkgPrefixActivated(final String pkgPrefix) {
    return reflectionsModel.isPkgPrefixActivated(pkgPrefix);
  }

  public static boolean isPkgPrefixActivated(final Class clazz) {
    return reflectionsModel.isPkgPrefixActivated(clazz.getPackage().getName());
  }

  public static LocalDateTime getPkgPrefixActivatedTimestamp(final String pkgPrefix) {
    return reflectionsModel.getPkgPrefixActivatedTimestamp(pkgPrefix);
  }

  public static  Set> getSubTypesOf(final Class type) {
    return reflectionsModel.getSubTypesOf(type);
  }

  public static  Set> getSubTypesWithoutInterfacesAndGeneratedOf(final Class type) {
    return reflectionsModel.getSubTypesWithoutInterfacesAndGeneratedOf(type);
  }

  public static Set> getTypesAnnotatedWith(final Class annotation) {
    return reflectionsModel.getTypesAnnotatedWith(annotation);
  }

  public static Set> getTypesAnnotatedWith(final Class annotation, final boolean honorInherited) {
    return reflectionsModel.getTypesAnnotatedWith(annotation, honorInherited);
  }

  public static Set> getTypesAnnotatedWith(final Annotation annotation) {
    return reflectionsModel.getTypesAnnotatedWith(annotation);
  }

  public static Set> getTypesAnnotatedWith(final Annotation annotation, final boolean honorInherited) {
    return reflectionsModel.getTypesAnnotatedWith(annotation, honorInherited);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy