package com.twelvemonkeys.servlet.log4j; import org.apache.log4j.Logger; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import java.io.InputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.MalformedURLException; import java.net.URL; import java.util.Enumeration; import java.util.Set; /** * Log4JContextWrapper * <p/> * * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @version $Id: log4j/Log4JContextWrapper.java#1 $ */ final class Log4JContextWrapper implements ServletContext { // TODO: Move to sandbox // TODO: This solution sucks... // How about starting to create some kind of pluggable decorator system, // something along the lines of AOP mixins/interceptor pattern.. // Probably using a dynamic Proxy, delegating to the mixins and or the // wrapped object based on configuration. // This way we could simply call ServletUtil.decorate(ServletContext):ServletContext // And the context would be decorated with all configured mixins at once, // requiring less boilerplate delegation code, and less layers of wrapping // (alternatively we could decorate the Servlet/FilterConfig objects). // See the ServletUtil.createWrapper methods for some hints.. // Something like this: public static ServletContext wrap(final ServletContext pContext, final Object[] pDelegates, final ClassLoader pLoader) { ClassLoader cl = pLoader != null ? pLoader : Thread.currentThread().getContextClassLoader(); // TODO: Create a "static" mapping between methods in the ServletContext // and the corresponding delegate // TODO: Resolve super-invokations, to delegate to next delegate in // chain, and finally invoke pContext return (ServletContext) Proxy.newProxyInstance(cl, new Class[] {ServletContext.class}, new InvocationHandler() { public Object invoke(Object pProxy, Method pMethod, Object[] pArgs) throws Throwable { // TODO: Test if any of the delegates should receive, if so invoke // Else, invoke on original object return pMethod.invoke(pContext, pArgs); } }); } private final ServletContext context; private final Logger logger; Log4JContextWrapper(ServletContext pContext) { context = pContext; // TODO: We want a logger per servlet, not per servlet context, right? logger = Logger.getLogger(pContext.getServletContextName()); // TODO: Automatic init/config of Log4J using context parameter for log4j.xml? // See Log4JInit.java // TODO: Automatic config of properties in the context wrapper? } public final void log(final Exception pException, final String pMessage) { log(pMessage, pException); } // TODO: Add more logging methods to interface info/warn/error? // TODO: Implement these mehtods in GenericFilter/GenericServlet? public void log(String pMessage) { // TODO: Get logger for caller.. // Should be possible using some stack peek hack, but that's slow... // Find a good way... // Maybe just pass it into the constuctor, and have one wrapper per servlet logger.info(pMessage); } public void log(String pMessage, Throwable pCause) { // TODO: Get logger for caller.. logger.error(pMessage, pCause); } public Object getAttribute(String pMessage) { return context.getAttribute(pMessage); } public Enumeration getAttributeNames() { return context.getAttributeNames(); } public ServletContext getContext(String pMessage) { return context.getContext(pMessage); } public String getInitParameter(String pMessage) { return context.getInitParameter(pMessage); } public Enumeration getInitParameterNames() { return context.getInitParameterNames(); } public int getMajorVersion() { return context.getMajorVersion(); } public String getMimeType(String pMessage) { return context.getMimeType(pMessage); } public int getMinorVersion() { return context.getMinorVersion(); } public RequestDispatcher getNamedDispatcher(String pMessage) { return context.getNamedDispatcher(pMessage); } public String getRealPath(String pMessage) { return context.getRealPath(pMessage); } public RequestDispatcher getRequestDispatcher(String pMessage) { return context.getRequestDispatcher(pMessage); } public URL getResource(String pMessage) throws MalformedURLException { return context.getResource(pMessage); } public InputStream getResourceAsStream(String pMessage) { return context.getResourceAsStream(pMessage); } public Set getResourcePaths(String pMessage) { return context.getResourcePaths(pMessage); } public String getServerInfo() { return context.getServerInfo(); } public Servlet getServlet(String pMessage) throws ServletException { //noinspection deprecation return context.getServlet(pMessage); } public String getServletContextName() { return context.getServletContextName(); } public Enumeration getServletNames() { //noinspection deprecation return context.getServletNames(); } public Enumeration getServlets() { //noinspection deprecation return context.getServlets(); } public void removeAttribute(String pMessage) { context.removeAttribute(pMessage); } public void setAttribute(String pMessage, Object pExtension) { context.setAttribute(pMessage, pExtension); } }