package org.jboss.weld.servlet.core.tomcat7;
import static org.jboss.weld.environment.servlet.util.Reflections.findDeclaredField;
import static org.jboss.weld.environment.servlet.util.Reflections.findDeclaredMethod;
import static org.jboss.weld.environment.servlet.util.Reflections.getFieldValue;
import static org.jboss.weld.environment.servlet.util.Reflections.invokeMethod;
import static org.jboss.weld.environment.servlet.util.Reflections.setFieldValue;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.servlet.ServletContextEvent;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.ApplicationContextFacade;
import org.apache.catalina.core.DefaultInstanceManager;
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.InstanceManager;
import org.jboss.weld.environment.servlet.util.Reflections;
import org.jboss.weld.manager.api.WeldManager;
/**
* @author Matija Mazi
*
* Forwards all calls in turn to two delegates: first to
* originalAnnotationProcessor, then to weldProcessor.
*/
public class WeldForwardingInstanceManager extends ForwardingInstanceManager {
private final InstanceManager firstProcessor;
private final InstanceManager secondProcessor;
public WeldForwardingInstanceManager(
InstanceManager originalAnnotationProcessor,
InstanceManager weldProcessor) {
this.firstProcessor = originalAnnotationProcessor;
this.secondProcessor = weldProcessor;
}
@Override
protected InstanceManager delegate() {
return firstProcessor;
}
@Override
public void destroyInstance(Object arg0) throws IllegalAccessException,
InvocationTargetException {
// TODO Auto-generated method stub
super.destroyInstance(arg0);
secondProcessor.destroyInstance(arg0);
}
@Override
public void newInstance(Object arg0) throws IllegalAccessException,
InvocationTargetException, NamingException {
super.newInstance(arg0);
secondProcessor.newInstance(arg0);
}
@Override
public Object newInstance(String arg0, ClassLoader arg1)
throws IllegalAccessException, InvocationTargetException,
NamingException, InstantiationException, ClassNotFoundException {
Object a = super.newInstance(arg0, arg1);
secondProcessor.newInstance(a);
return a;
}
@Override
public Object newInstance(String arg0) throws IllegalAccessException,
InvocationTargetException, NamingException, InstantiationException,
ClassNotFoundException {
Object a = super.newInstance(arg0);
secondProcessor.newInstance(a);
return a;
}
public static void replaceAnnotationProcessor(ServletContextEvent sce,
WeldManager manager) {
StandardContext stdContext = getStandardContext(sce);
setAnnotationProcessor(stdContext, createInstance(manager, stdContext));
}
private static WeldForwardingInstanceManager createInstance(WeldManager manager, StandardContext stdContext)
{
try
{
InstanceManager weldProcessor = new WeldInstanceManager(manager);
return new WeldForwardingInstanceManager(getAnnotationProcessor(stdContext), weldProcessor);
}
catch (Exception e)
{
throw new RuntimeException("Cannot create WeldForwardingAnnotationProcessor", e);
}
}
private static StandardContext getStandardContext(ServletContextEvent sce) {
try {
// Hack into Tomcat to replace the AnnotationProcessor using
// reflection to access private fields
ApplicationContext appContext = (ApplicationContext) getContextFieldValue(
(ApplicationContextFacade) sce.getServletContext(),
ApplicationContextFacade.class);
return (StandardContext) getContextFieldValue(appContext,
ApplicationContext.class);
} catch (Exception e) {
throw new RuntimeException(
"Cannot get StandardContext from ServletContext", e);
}
}
private static Object getContextFieldValue(E obj, Class clazz)
throws NoSuchFieldException, IllegalAccessException {
Field f = clazz.getDeclaredField("context");
f.setAccessible(true);
return f.get(obj);
}
public static void restoreAnnotationProcessor(ServletContextEvent sce) {
StandardContext stdContext = getStandardContext(sce);
InstanceManager ap = getAnnotationProcessor(stdContext);
if (ap instanceof WeldForwardingInstanceManager) {
setAnnotationProcessor(stdContext,
((WeldForwardingInstanceManager) ap).firstProcessor);
}
}
private static InstanceManager getAnnotationProcessor(
StandardContext stdContext) {
return stdContext.getInstanceManager();
}
private static void setAnnotationProcessor(StandardContext stdContext,
InstanceManager instanceManager) {
stdContext.setInstanceManager(instanceManager);
}
}