Skip to content

Commit

Permalink
add test, if there is a factory for default beans
Browse files Browse the repository at this point in the history
Define default beans (e.g. ContextService) only if there is no factory
generating them.
  • Loading branch information
aubi committed May 9, 2024
1 parent f5e86fd commit fb51a2e
Showing 1 changed file with 91 additions and 119 deletions.
210 changes: 91 additions & 119 deletions src/main/java/org/glassfish/concurro/cdi/ConcurrentCDIExtension.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@
import jakarta.enterprise.inject.Default;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
import jakarta.enterprise.inject.spi.AfterDeploymentValidation;
import jakarta.enterprise.inject.spi.AnnotatedMethod;
import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.BeforeBeanDiscovery;
import jakarta.enterprise.inject.spi.BeforeShutdown;
import jakarta.enterprise.inject.spi.Extension;
import jakarta.enterprise.inject.spi.ProcessAnnotatedType;
import jakarta.enterprise.inject.spi.ProcessInjectionTarget;
import jakarta.enterprise.inject.spi.ProcessProducer;
import jakarta.enterprise.inject.spi.ProcessBean;
import jakarta.enterprise.inject.spi.WithAnnotations;
import jakarta.transaction.Transactional;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
Expand All @@ -60,6 +60,10 @@
public class ConcurrentCDIExtension implements Extension {

private static final Logger log = Logger.getLogger(ConcurrentCDIExtension.class.getName());
private boolean isCSProduced = false;
private boolean isMTFProduced = false;
private boolean isMESProduced = false;
private boolean isMSESProduced = false;

public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery beforeBeanDiscovery, BeanManager beanManager) {
log.finest("ConcurrentCDIExtension.beforeBeanDiscovery");
Expand All @@ -70,6 +74,14 @@ public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery beforeBeanDiscover
beforeBeanDiscovery.addAnnotatedType(asynchronousInterceptor, AsynchronousInterceptor.class.getName());
}

/**
* Check correct usage of the {@link Asynchronous} annotation.
*
* @param <T>
* @param processAnnotatedType
* @param beanManager
* @throws Exception
*/
public <T> void processAnnotatedType(@Observes @WithAnnotations({Asynchronous.class}) ProcessAnnotatedType<T> processAnnotatedType,
BeanManager beanManager) throws Exception {
log.finest("ConcurrentCDIExtension.processAnnotatedType");
Expand Down Expand Up @@ -107,88 +119,66 @@ public <T> void processAnnotatedType(@Observes @WithAnnotations({Asynchronous.cl
}

/**
* 1: BeforeBeanDiscovery.
*
* @param event
*/
public void beforeBeanDiscovery2(@Observes final BeforeBeanDiscovery event) {
log.severe("addScope");
}

/**
* 2: ProcessAnnotatedType.
*
* @param <T>
* @param processAnnotatedType
* @param beanManager
* @throws Exception
*/
public <T> void processAnyAnnotatedType(@Observes ProcessAnnotatedType<T> processAnnotatedType,
BeanManager beanManager) throws Exception {
log.severe("I'm here, class: " + processAnnotatedType.getClass());
if (processAnnotatedType.getClass().getName().startsWith("ee.")) {
log.severe("HERE!!!");
}
}

/**
* 3: ProcessInjectionTarget.
*
* @param <T>
* @param pit
*/
public <T> void processInjectionTarget(@Observes ProcessInjectionTarget<T> pit) {
if (pit.getAnnotatedType().getJavaClass().getName().startsWith("ee.")) {
// TOOD create contextual proxy
log.severe("processInjectionTarget " + pit.getInjectionTarget());
}
}

/**
* 4: ProcessProducer.
* Check, which default types are available via factories.
*
* @param <T>
* @param <X>
* @param event
*/
public <T, X> void processProducer(@Observes ProcessProducer<T, X> event) {
log.severe("processProducer, " + event.getProducer());
public <T> void processBean(@Observes ProcessBean<T> event) {
Bean<T> bean = event.getBean();
Set<Type> types = bean.getTypes();
log.finest(() -> "processBean, types: " + types);
log.finest(() -> "processBean, qualifiers: " + bean.getQualifiers());
// Check, if there is a producer method for the default beans
boolean defaultQualifiers = bean.getQualifiers().equals(new HashSet<>(Arrays.asList(Default.Literal.INSTANCE, Any.Literal.INSTANCE)));
isCSProduced |= types.contains(ContextService.class) && defaultQualifiers;
isMTFProduced |= types.contains(ManagedThreadFactory.class) && defaultQualifiers;
isMESProduced |= types.contains(ManagedExecutorService.class) && defaultQualifiers;
isMSESProduced |= types.contains(ManagedScheduledExecutorService.class) && defaultQualifiers;
}

/**
* 5: AfterBeanDiscovery.
* During AfterBeanDiscovery event, define the CDI beans depending on data
* collected during annotations scan.
*
* @param event
*/
void afterBeanDiscovery(@Observes final AfterBeanDiscovery event, BeanManager beanManager) {
try {
log.severe("afterBeanDiscovery");

// define default beans
event.addBean()
.beanClass(ContextService.class)
.types(ContextService.class)
.scope(ApplicationScoped.class)
.addQualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
.produceWith((Instance<Object> inst) -> createInstanceContextService(inst, "java:comp/DefaultContextService"));
event.addBean()
.beanClass(ManagedThreadFactory.class)
.types(ManagedThreadFactory.class)
.scope(ApplicationScoped.class)
.addQualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
.produceWith((Instance<Object> inst) -> createInstanceContextService(inst, "java:comp/DefaultManagedThreadFactory"));
event.addBean()
.beanClass(ManagedExecutorService.class)
.types(ManagedExecutorService.class)
.scope(ApplicationScoped.class)
.addQualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
.produceWith((Instance<Object> inst) -> createInstanceContextService(inst, "java:comp/DefaultManagedExecutorService"));
event.addBean()
.beanClass(ManagedScheduledExecutorService.class)
.types(ManagedScheduledExecutorService.class)
.scope(ApplicationScoped.class)
.addQualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
.produceWith((Instance<Object> inst) -> createInstanceContextService(inst, "java:comp/DefaultManagedScheduledExecutorService"));
if (!isCSProduced) {
event.addBean()
.beanClass(ContextService.class)
.types(ContextService.class)
.scope(ApplicationScoped.class)
.addQualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
.produceWith((Instance<Object> inst) -> createInstanceContextService(inst, "java:comp/DefaultContextService"));
}
if (!isMTFProduced) {
event.addBean()
.beanClass(ManagedThreadFactory.class)
.types(ManagedThreadFactory.class)
.scope(ApplicationScoped.class)
.addQualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
.produceWith((Instance<Object> inst) -> createInstanceContextService(inst, "java:comp/DefaultManagedThreadFactory"));
}
if (!isMESProduced) {
event.addBean()
.beanClass(ManagedExecutorService.class)
.types(ManagedExecutorService.class)
.scope(ApplicationScoped.class)
.addQualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
.produceWith((Instance<Object> inst) -> createInstanceContextService(inst, "java:comp/DefaultManagedExecutorService"));
}
if (!isMSESProduced) {
event.addBean()
.beanClass(ManagedScheduledExecutorService.class)
.types(ManagedScheduledExecutorService.class)
.scope(ApplicationScoped.class)
.addQualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
.produceWith((Instance<Object> inst) -> createInstanceContextService(inst, "java:comp/DefaultManagedScheduledExecutorService"));
}

// pick up ConcurrencyManagedCDIBeans definitions from JNDI
InitialContext ctx = new InitialContext();
Expand All @@ -198,60 +188,42 @@ void afterBeanDiscovery(@Observes final AfterBeanDiscovery event, BeanManager be
String jndiName = beanDefinition.jndiName();
Set<Annotation> annotations = new HashSet<>();
Set<String> classNames = beanDefinition.qualifiers();
for (String className : classNames) {
Class<? extends Annotation> annoCls = Thread.currentThread().getContextClassLoader().loadClass(className).asSubclass(Annotation.class);
Annotation annotationProxy = Annotation.class.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[]{Annotation.class, annoCls},
new QualifierAnnotationProxy(annoCls)));
annotations.add(annotationProxy);
if (!classNames.isEmpty()) {
for (String className : classNames) {
Class<? extends Annotation> annoCls = Thread.currentThread().getContextClassLoader().loadClass(className).asSubclass(Annotation.class);
Annotation annotationProxy = Annotation.class.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[]{Annotation.class, annoCls},
new QualifierAnnotationProxy(annoCls)));
annotations.add(annotationProxy);
}

Class<?> beanClass = switch (beanDefinition.definitionType()) {
case CONTEXT_SERVICE ->
ContextService.class;
case MANAGED_THREAD_FACTORY ->
ManagedThreadFactory.class;
case MANAGED_EXECUTOR_SERVICE ->
ManagedExecutorService.class;
case MANAGED_SCHEDULED_EXECUTOR_SERVICE ->
ManagedScheduledExecutorService.class;
};

// register bean
event.addBean()
.beanClass(beanClass)
.types(beanClass)
.scope(ApplicationScoped.class)
.addQualifiers(annotations)
.produceWith((Instance<Object> inst) -> createInstanceContextService(inst, jndiName));
}

Class<?> beanClass = switch (beanDefinition.definitionType()) {
case CONTEXT_SERVICE ->
ContextService.class;
case MANAGED_THREAD_FACTORY ->
ManagedThreadFactory.class;
case MANAGED_EXECUTOR_SERVICE ->
ManagedExecutorService.class;
case MANAGED_SCHEDULED_EXECUTOR_SERVICE ->
ManagedScheduledExecutorService.class;
};

// register bean
event.addBean()
.beanClass(beanClass)
.types(beanClass)
.scope(ApplicationScoped.class)
.addQualifiers(annotations)
.produceWith((Instance<Object> inst) -> createInstanceContextService(inst, jndiName));
}
} catch (NamingException ex) {
log.log(Level.SEVERE, "Unable to load '" + ConcurrencyManagedCDIBeans.JDNI_NAME + "' from JNDI! " + ex.getMessage(), ex);
log.log(Level.FINEST, "Unable to load '" + ConcurrencyManagedCDIBeans.JDNI_NAME + "' from JNDI, probably no concurrency definitions annotations found during scanning " + ex.getMessage(), ex);
} catch (ClassNotFoundException ex) {
log.log(Level.SEVERE, ex.getMessage(), ex);
log.log(Level.SEVERE, "Unable to load class from application's classloader: " + ex.getMessage(), ex);
}
}

/**
* 6. AfterDeploymentValidation.
*
* @param event
* @param beanManager
*/
public void afterDeploymentValidation(@Observes AfterDeploymentValidation event, BeanManager beanManager) {
log.severe("afterDeploymentValidation");
}

/**
* 7: BeforeShutdown.
*
* @param event
* @param beanManager
*/
public void beforeShutdown(@Observes BeforeShutdown event, BeanManager beanManager) {
log.severe("beforeShutdown");
}

// This is not working as the annotation doesn't need to be on CDI bean
// public <T> void processAnnotatedType(@Observes @WithAnnotations(ContextServiceDefinition.class) ProcessAnnotatedType<T> pat) {
// }
Expand Down

0 comments on commit fb51a2e

Please sign in to comment.