package org.gatein.cdi;
import org.gatein.common.logging.Logger;
import org.gatein.common.logging.LoggerFactory;
import org.gatein.pc.portlet.container.PortletApplication;
import org.gatein.pc.portlet.container.managed.LifeCycleStatus;
import org.gatein.pc.portlet.container.managed.ManagedObject;
import org.gatein.pc.portlet.container.managed.ManagedObjectAddedEvent;
import org.gatein.pc.portlet.container.managed.ManagedObjectLifeCycleEvent;
import org.gatein.pc.portlet.container.managed.ManagedObjectRegistryEvent;
import org.gatein.pc.portlet.container.managed.ManagedObjectRegistryEventListener;
import org.gatein.pc.portlet.container.managed.ManagedPortletContainer;
import org.gatein.pc.portlet.container.managed.ManagedPortletFilter;
import org.gatein.pc.portlet.impl.jsr168.PortletFilterImpl;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.portlet.Portlet;
import javax.portlet.filter.ActionFilter;
import javax.portlet.filter.EventFilter;
import javax.portlet.filter.PortletFilter;
import javax.portlet.filter.RenderFilter;
import javax.portlet.filter.ResourceFilter;
import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="http://community.jboss.org/people/kenfinni">Ken Finnigan</a>
*/
public class CDIInjectionListener implements ManagedObjectRegistryEventListener {
private final Logger log = LoggerFactory.getLogger(CDIInjectionListener.class);
private static final String BEAN_MGR_ATTRIBUTE = "javax.enterprise.inject.spi.BeanManager";
private static final String SERVLET_BEAN_MGR_ATTRIBUTE = "org.jboss.weld.environment.servlet.javax.enterprise.inject.spi.BeanManager";
private Map<String, CDIMetaData> cdiMetaDataMap = new ConcurrentHashMap<String, CDIMetaData>();
private List<Class<? extends PortletFilter>> filterClasses = new ArrayList<Class<? extends PortletFilter>>();
public CDIInjectionListener() {
filterClasses.add(ActionFilter.class);
filterClasses.add(EventFilter.class);
filterClasses.add(RenderFilter.class);
filterClasses.add(ResourceFilter.class);
}
@Override
public void onEvent(ManagedObjectRegistryEvent event) {
if (event instanceof ManagedObjectAddedEvent) {
// Track whether a portletContainer or portletFilter needs CDI injection
ManagedObject managedObject = ((ManagedObjectAddedEvent) event).getManagedObject();
if (managedObject instanceof ManagedPortletContainer) {
ManagedPortletContainer managedPortletContainer = (ManagedPortletContainer) managedObject;
PortletApplication portletApp = managedPortletContainer.getManagedPortletApplication().getPortletApplication();
createMetaData(managedPortletContainer.getId(), portletApp);
} else if (managedObject instanceof ManagedPortletFilter) {
ManagedPortletFilter managedPortletFilter = (ManagedPortletFilter) managedObject;
PortletApplication portletApp = managedPortletFilter.getManagedPortletApplication().getPortletApplication();
createMetaData(managedPortletFilter.getId(), portletApp);
}
} else if (event instanceof ManagedObjectLifeCycleEvent) {
ManagedObjectLifeCycleEvent lifeCycleEvent = (ManagedObjectLifeCycleEvent) event;
ManagedObject managedObject = lifeCycleEvent.getManagedObject();
LifeCycleStatus status = lifeCycleEvent.getStatus();
if (managedObject instanceof ManagedPortletContainer) {
if (LifeCycleStatus.STARTED == status || LifeCycleStatus.INITIALIZED == status) {
return;
}
ManagedPortletContainer managedPortletContainer = (ManagedPortletContainer) managedObject;
CDIMetaData cdiMetaData = cdiMetaDataMap.get(managedPortletContainer.getId());
if (!cdiMetaData.cdiInjectionEnabled) {
return;
}
Portlet portlet = managedPortletContainer.getPortletInstance();
if (null != portlet) {
if (null != portlet.getClass() && "javax.portlet.faces.GenericFacesPortlet".equals(portlet.getClass().getName())) {
// Only perform injection on non JSF portlets
cdiMetaData.cdiInjectionEnabled = false;
cdiMetaDataMap.put(cdiMetaData.key, cdiMetaData);
return;
}
PortletApplication portletApp = managedPortletContainer.getManagedPortletApplication().getPortletApplication();
if (!cdiMetaData.injectionPerformed) {
performInjection(portlet, cdiMetaData, portletApp.getContext().getServletContext());
} else {
performCleanup(portlet, cdiMetaData, portletApp.getContext().getServletContext());
}
}
} else if (managedObject instanceof ManagedPortletFilter) {
if (LifeCycleStatus.INITIALIZED == status) {
return;
}
ManagedPortletFilter managedPortletFilter = (ManagedPortletFilter) managedObject;
CDIMetaData cdiMetaData = cdiMetaDataMap.get(managedPortletFilter.getId());
if (!cdiMetaData.cdiInjectionEnabled) {
return;
}
PortletFilterImpl portletFilterImpl = (PortletFilterImpl) managedPortletFilter.getPortletFilter();
PortletFilter portletFilterInstance;
for (Class type : filterClasses) {
portletFilterInstance = (PortletFilter) portletFilterImpl.instance(type);
if (null != portletFilterInstance) {
PortletApplication portletApp = managedPortletFilter.getManagedPortletApplication().getPortletApplication();
if (LifeCycleStatus.STARTED == status && !cdiMetaData.injectionPerformed) {
performInjection(portletFilterInstance, cdiMetaData, portletApp.getContext().getServletContext());
} else if (LifeCycleStatus.CREATED == status && cdiMetaData.injectionPerformed) {
performCleanup(portletFilterInstance, cdiMetaData, portletApp.getContext().getServletContext());
}
break;
}
}
}
}
}
private void createMetaData(String id, PortletApplication portletApp) {
CDIMetaData metaData = new CDIMetaData();
metaData.key = id;
if (null != portletApp.getContext().getServletContext().getAttribute(BEAN_MGR_ATTRIBUTE)) {
metaData.cdiInjectionEnabled = true;
} else {
Object beanManager = portletApp.getContext().getServletContext().getAttribute(SERVLET_BEAN_MGR_ATTRIBUTE);
if (null != beanManager) {
metaData.cdiInjectionEnabled = true;
portletApp.getContext().getServletContext().setAttribute(BEAN_MGR_ATTRIBUTE, beanManager);
}
}
cdiMetaDataMap.put(id, metaData);
}
private void performInjection(Object instance, CDIMetaData metaData, ServletContext servletContext) {
// Perform CDI injection
Object beanManagerObject = servletContext.getAttribute(BEAN_MGR_ATTRIBUTE);
if (null == beanManagerObject) {
log.error("Unable to retrieve BeanManager from ServletContext");
return;
}
ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(servletContext.getClassLoader());
BeanManager beanManager = (BeanManager) beanManagerObject;
CreationalContext creationalContext = beanManager.createCreationalContext(null);
InjectionTarget injectionTarget = beanManager.createInjectionTarget(beanManager.createAnnotatedType(instance.getClass()));
injectionTarget.inject(instance, creationalContext);
Thread.currentThread().setContextClassLoader(oldCL);
metaData.injectionPerformed = true;
metaData.creationalContext = creationalContext;
metaData.injectionTarget = injectionTarget;
cdiMetaDataMap.put(metaData.key, metaData);
}
private void performCleanup(Object instance, CDIMetaData metaData, ServletContext servletContext) {
// Perform CDI cleanup
InjectionTarget injectionTarget = metaData.injectionTarget;
CreationalContext creationalContext = metaData.creationalContext;
ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(servletContext.getClassLoader());
if (null != injectionTarget) {
injectionTarget.dispose(instance);
metaData.injectionTarget = null;
}
if (null != creationalContext) {
creationalContext.release();
metaData.creationalContext = null;
}
Thread.currentThread().setContextClassLoader(oldCL);
metaData.injectionPerformed = false;
cdiMetaDataMap.put(metaData.key, metaData);
}
private class CDIMetaData {
private String key;
private boolean cdiInjectionEnabled = false;
private boolean injectionPerformed = false;
private InjectionTarget injectionTarget;
private CreationalContext creationalContext;
}
}