package org.jboss.resteasy.cdi;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.CDI;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import org.jboss.resteasy.cdi.i18n.LogMessages;
import org.jboss.resteasy.cdi.i18n.Messages;
import org.jboss.resteasy.core.InjectorFactoryImpl;
import org.jboss.resteasy.core.ResteasyContext;
import org.jboss.resteasy.spi.ConstructorInjector;
import org.jboss.resteasy.spi.InjectorFactory;
import org.jboss.resteasy.spi.MethodInjector;
import org.jboss.resteasy.spi.PropertyInjector;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.ValueInjector;
import org.jboss.resteasy.spi.metadata.Parameter;
import org.jboss.resteasy.spi.metadata.ResourceClass;
import org.jboss.resteasy.spi.metadata.ResourceConstructor;
import org.jboss.resteasy.spi.metadata.ResourceLocator;
@SuppressWarnings("rawtypes")
public class CdiInjectorFactory implements InjectorFactory
{
public static final String BEAN_MANAGER_ATTRIBUTE_PREFIX = "org.jboss.weld.environment.servlet.";
private BeanManager manager;
private InjectorFactory delegate = new InjectorFactoryImpl();
private ResteasyCdiExtension extension;
private Map<Class<?>, Type> sessionBeanInterface;
public CdiInjectorFactory()
{
this.manager = lookupBeanManager();
this.extension = lookupResteasyCdiExtension();
sessionBeanInterface = extension.getSessionBeanInterface();
}
public CdiInjectorFactory(final BeanManager manager)
{
this.manager = manager;
this.extension = lookupResteasyCdiExtension();
sessionBeanInterface = extension.getSessionBeanInterface();
}
@Override
public ValueInjector (Parameter parameter, ResteasyProviderFactory providerFactory)
{
return delegate.createParameterExtractor(parameter, providerFactory);
}
@Override
public MethodInjector createMethodInjector(ResourceLocator method, ResteasyProviderFactory factory)
{
return delegate.createMethodInjector(method, factory);
}
@Override
public PropertyInjector createPropertyInjector(ResourceClass resourceClass, ResteasyProviderFactory providerFactory)
{
return new CdiPropertyInjector(delegate.createPropertyInjector(resourceClass, providerFactory), resourceClass.getClazz(), sessionBeanInterface, manager);
}
@Override
public ConstructorInjector createConstructor(ResourceConstructor constructor, ResteasyProviderFactory providerFactory)
{
Class<?> clazz = constructor.getConstructor().getDeclaringClass();
ConstructorInjector injector = cdiConstructor(clazz);
if (injector != null) return injector;
LogMessages.LOGGER.debug(Messages.MESSAGES.noCDIBeansFound(clazz));
return delegate.createConstructor(constructor, providerFactory);
}
@Override
public ConstructorInjector createConstructor(Constructor constructor, ResteasyProviderFactory factory)
{
Class<?> clazz = constructor.getDeclaringClass();
ConstructorInjector injector = cdiConstructor(clazz);
if (injector != null) return injector;
LogMessages.LOGGER.debug(Messages.MESSAGES.noCDIBeansFound(clazz));
return delegate.createConstructor(constructor, factory);
}
protected ConstructorInjector cdiConstructor(Class<?> clazz)
{
if (!manager.getBeans(clazz).isEmpty())
{
LogMessages.LOGGER.debug(Messages.MESSAGES.usingCdiConstructorInjector(clazz));
return new CdiConstructorInjector(clazz, manager);
}
if (sessionBeanInterface.containsKey(clazz))
{
Type intfc = sessionBeanInterface.get(clazz);
LogMessages.LOGGER.debug(Messages.MESSAGES.usingInterfaceForLookup(intfc, clazz));
return new CdiConstructorInjector(intfc, manager);
}
return null;
}
public PropertyInjector createPropertyInjector(Class resourceClass, ResteasyProviderFactory factory)
{
return new CdiPropertyInjector(delegate.createPropertyInjector(resourceClass, factory), resourceClass, sessionBeanInterface, manager);
}
public ValueInjector (Class injectTargetClass, AccessibleObject injectTarget, String defaultName, Class type, Type genericType, Annotation[] annotations, ResteasyProviderFactory factory)
{
return delegate.createParameterExtractor(injectTargetClass, injectTarget, defaultName, type, genericType, annotations, factory);
}
public ValueInjector (Class injectTargetClass, AccessibleObject injectTarget, String defaultName, Class type,
Type genericType, Annotation[] annotations, boolean useDefault, ResteasyProviderFactory factory)
{
return delegate.createParameterExtractor(injectTargetClass, injectTarget, defaultName, type, genericType, annotations, useDefault, factory);
}
protected BeanManager lookupBeanManager()
{
BeanManager beanManager = null;
beanManager = lookupBeanManagerInJndi("java:comp/BeanManager");
if (beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerAtJavaComp());
return beanManager;
}
beanManager = lookupBeanManagerInJndi("java:app/BeanManager");
if (beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerAtJavaApp());
return beanManager;
}
beanManager = lookupBeanManagerCDIUtil();
if(beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerViaCDI());
return beanManager;
}
beanManager = lookupBeanManagerViaServletContext();
if(beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerInServletContext());
return beanManager;
}
throw new RuntimeException(Messages.MESSAGES.unableToLookupBeanManager());
}
private BeanManager lookupBeanManagerInJndi(String name)
{
try
{
InitialContext ctx = new InitialContext();
LogMessages.LOGGER.debug(Messages.MESSAGES.doingALookupForBeanManager(name));
return (BeanManager) ctx.lookup(name);
}
catch (NamingException e)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.unableToObtainBeanManager(name));
return null;
}
catch (NoClassDefFoundError ncdfe)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.unableToPerformJNDILookups());
return null;
}
}
private static BeanManager lookupBeanManagerViaServletContext()
{
BeanManager beanManager = null;
try
{
ServletContext servletContext = ResteasyContext.getContextData(ServletContext.class);
if (servletContext != null)
{
beanManager = (BeanManager) servletContext.getAttribute(BEAN_MANAGER_ATTRIBUTE_PREFIX + BeanManager.class.getName());
if (beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerInServletContext());
return beanManager;
}
beanManager = (BeanManager) servletContext.getAttribute(BeanManager.class.getName());
if (beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerInServletContext());
return beanManager;
}
}
}
catch (NoClassDefFoundError e)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.unableToFindServletContextClass(), e);
}
catch (Exception e)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.errorOccurredLookingUpServletContext(), e);
}
return beanManager;
}
public static BeanManager lookupBeanManagerCDIUtil()
{
BeanManager bm = null;
try
{
bm = CDI.current().getBeanManager();
}
catch (NoClassDefFoundError e)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.unableToFindCDIClass(), e);
}
catch (Exception e)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.errorOccurredLookingUpViaCDIUtil(), e);
}
return bm;
}
private ResteasyCdiExtension lookupResteasyCdiExtension()
{
Set<Bean<?>> beans = manager.getBeans(ResteasyCdiExtension.class);
Bean<?> bean = manager.resolve(beans);
if (bean == null)
{
throw new IllegalStateException(Messages.MESSAGES.unableToObtainResteasyCdiExtension());
}
CreationalContext<?> context = manager.createCreationalContext(bean);
return (ResteasyCdiExtension) manager.getReference(bean, ResteasyCdiExtension.class, context);
}
}