package com.blazebit.cdi.exclude; import java.lang.annotation.Annotation; import java.lang.reflect.Member; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.enterprise.context.Dependent; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.Disposes; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedParameter; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.InjectionPoint; import javax.enterprise.inject.spi.Producer; import org.apache.deltaspike.core.util.BeanUtils; import org.apache.deltaspike.core.util.metadata.builder.ContextualLifecycle; public class ProducerMethodCreationalContext implements ContextualLifecycle<Object> { private final Bean<Object> declaringBean; private final AnnotatedMethod<?> producerMethod; private final AnnotatedMethod<?> disposalMethod; private final List<InjectionPoint> producerInjectionPoints; private final List<InjectionPoint> disposalInjectionPoints; private final BeanManager beanManager; public ProducerMethodCreationalContext(Bean<Object> declaringBean, AnnotatedMethod<?> producerMethod, BeanManager beanManager, boolean isOwbAndDependentScope) { this.declaringBean = declaringBean; this.producerMethod = producerMethod; this.producerInjectionPoints = BeanUtils.createInjectionPoints(producerMethod, declaringBean, beanManager); this.disposalMethod = findDisposalMethod(); if (this.disposalMethod != null) { if (isOwbAndDependentScope) { throw new IllegalArgumentException("Due to a bug in OpenWebBeans the disposal method '" + disposalMethod.getJavaMember().getName() + "' of the class '" + disposalMethod.getDeclaringType().getJavaClass().getName() + "' will never be called in conjunction with the ExcludeIfExists extension. " + "Therefore the disposal method should be removed!"); } this.disposalInjectionPoints = BeanUtils.createInjectionPoints(disposalMethod, declaringBean, beanManager); } else { this.disposalInjectionPoints = null; } this.beanManager = beanManager; } private AnnotatedMethod<?> findDisposalMethod() { for (AnnotatedMethod<?> m : producerMethod.getDeclaringType().getMethods()) { if (m == producerMethod) { continue; } for (AnnotatedParameter<?> p : m.getParameters()) { if (p.getAnnotation(Disposes.class) == null) { continue; } // p is the disposes parameter if (p.getBaseType().equals(producerMethod.getBaseType())) { return m; } // if we found a disposes parameter that doesn't match the producer type, we can skip this method break; } } return null; } @Override public Object create(Bean<Object> bean, CreationalContext<Object> creationalContext) { CreationalContext<Object> parentCreationalContext = null; InjectableMethod m; try { parentCreationalContext = beanManager.createCreationalContext(declaringBean); Object parentInstance = beanManager.getReference(declaringBean, declaringBean.getBeanClass(), parentCreationalContext); m = new InjectableMethod(producerMethod, parentInstance, declaringBean, creationalContext, beanManager, producerInjectionPoints); return m.doInjection(); } finally { if (parentCreationalContext != null) { parentCreationalContext.release(); } } } @Override public void destroy(Bean<Object> bean, Object instance, CreationalContext<Object> creationalContext) { if (disposalMethod != null) { CreationalContext<Object> parentCreationalContext = null; try { parentCreationalContext = beanManager.createCreationalContext(declaringBean); Object parentInstance = beanManager.getReference(declaringBean, declaringBean.getBeanClass(), parentCreationalContext); InjectableMethod m = new InjectableMethod(disposalMethod, parentInstance, declaringBean, creationalContext, beanManager, disposalInjectionPoints); m.setDisposable(true); m.setProducerMethodInstance(instance); m.doInjection(); } finally { if (parentCreationalContext != null) { parentCreationalContext.release(); } } } } public Set<InjectionPoint> getInjectionPoints() { return new HashSet<InjectionPoint>(producerInjectionPoints); } protected static List<InjectionPoint> createInjectionPoints(Producer<?> owner, Member member) { List<InjectionPoint> injectionPoints = new ArrayList<InjectionPoint>(); for (InjectionPoint injectionPoint : owner.getInjectionPoints()) { if (injectionPoint.getMember().equals(member)) { injectionPoints.add(injectionPoint); } } return injectionPoints; } }