/*
 * $Id$
 * $URL$
 */

package org.subethamail.web.servlet;

import java.io.IOException;
import java.net.URL;

import javax.inject.Inject;
import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.subethamail.common.NotFoundException;
import org.subethamail.core.lists.i.ListMgr;
import org.subethamail.web.util.AbstractFilter;

/**
 * This is a little trick that lets mailing lists "claim" any URL that successfully
 * resolves to this server.  Mounted on /*, this filter will try to resolve any
 * request normally - but if the result is 404, it will try to lookup the URL as
 * a mailing list URL.  If it finds one, it forwards to the list page.  Finally
 * as a last resort if it can do nothing else it will return 404.
 */
public class ListFilter extends AbstractFilter
{
	private static final long serialVersionUID = 1L;
	private final static Logger log = LoggerFactory.getLogger(ListFilter.class);
	
	/** */
	public static final String LIST_PAGE = "/list.jsp";
	public static final String ID_PARAM_NAME = "listId";
	
	public static final String WELCOME_PAGE = "/welcome.jsp";

	/** Good for shunting output to the bitbucket */
	static final ServletOutputStream NOOP_OUTPUTSTREAM = new ServletOutputStream() {
		@Override public void write(int b) throws IOException {}
		@Override public void write(byte[] b, int off, int len) throws IOException {}
	};
	
	/**
	 * <p>An {@link HttpServletResponseWrapper} that traps HTTP errors by
	 * overriding {@code sendError(int, ..)}.  If the error is 404,
	 * anything written is abandoned.  If the response is anything else,
	 * it is passed through as-is.</p>
	 * 
	 * <p>Note that this wrapper translates getWriter() calls into
	 * getOutputStream() calls to work around broken containers (and
	 * broken specs).
	 */
	public class TrappingResponseWrapper extends HttpServletResponseWrapper
	{
		/** True when we get a 404 */
		boolean trapped;
		
		/** Wrap the given {@code response}. */
		public TrappingResponseWrapper(HttpServletResponse response)
		{
			super(response);
		}

		/** */
		@Override
		public void sendError(int errorCode, String errorMessage) throws IOException
		{
			if (errorCode == HttpServletResponse.SC_NOT_FOUND)
			{
				log.debug("Got 404, trapping error");
				this.trapped = true;
			}
			else
				super.sendError(errorCode, errorMessage);
		}

		/** */
		@Override
		public void sendError(int errorCode) throws IOException
		{
			if (errorCode == HttpServletResponse.SC_NOT_FOUND)
			{
				log.debug("Got 404, trapping error");
				this.trapped = true;
			}
			else
				super.sendError(errorCode);
		}

		/** */
		@Override
		public ServletOutputStream getOutputStream() throws IOException
		{
			if (log.isDebugEnabled())
				log.debug("Getting a " + ((this.trapped)?"NOOP":"real")  + " OutputStream");
			
			if (this.trapped)
				return NOOP_OUTPUTSTREAM;
			else
				return super.getOutputStream();
		}

		/**
		 */
		public boolean isTrapped() { return this.trapped; }
	}
	
	/**
	 */
	@Inject ListMgr listMgr;
	
	/* (non-Javadoc)
	 * @see org.subethamail.web.util.AbstractFilter#doFilter(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
	 */
	@Override
	public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException
	{
		// We only work for GET requests
		if (!"GET".equals(request.getMethod()))
		{
			chain.doFilter(request, response);
			return;
		}
		
		// First try to process the request normally.  If we get 404, we need
		// to check for a special list address.
		TrappingResponseWrapper responseWrapper = new TrappingResponseWrapper(response);
		chain.doFilter(request, responseWrapper);
		
		// Maybe we're already done
		if (!responseWrapper.isTrapped())
			return;

		// Apparently not, let's lookup the URL and see if we have a hit
		String urlString = request.getRequestURL().toString();
		URL url = new URL(urlString);
		
		try
		{
			Long listId = listMgr.lookup(url);
			
			RequestDispatcher dispatcher = 
				request.getRequestDispatcher(LIST_PAGE + "?" + ID_PARAM_NAME + "=" + listId);
			
			dispatcher.forward(request, response);
		}
		catch (NotFoundException ex)
		{
			RequestDispatcher dispatcher = request.getRequestDispatcher(WELCOME_PAGE);
			dispatcher.forward(request, response);
		}
	}
}

@@ -113,16 +113,49 @@
 et.URL;%0D
+%0Aimport java.util.logging.Level;%0D
 %0A%0D%0Aimpor
@@ -500,60 +500,35 @@
 ort 
-org.slf4j.Logger;%0D%0Aimport org.slf4j.LoggerFactory
+lombok.extern.java.Log
 ;%0D%0A
+%0D%0A
 impo
@@ -1076,16 +1076,22 @@
 .%0D%0A */%0D%0A
+@Log%0D%0A
 public c
@@ -1188,87 +1188,8 @@
 L;%0D%0A
-%09private final static Logger log = LoggerFactory.getLogger(ListFilter.class);%0D%0A
 %09%0D%0A%09
@@ -2512,35 +2512,47 @@
 )%0D%0A%09%09%09%7B%0D%0A%09%09%09
-%09log.debug(
+    log.log(Level.FINE,
 %22Got 404, tr
@@ -2814,27 +2814,39 @@
 %09%09%7B%0D%0A%09%09%09
-%09log.debug(
+    log.log(Level.FINE,
 %22Got 404
@@ -3040,25 +3040,28 @@
 ion%0D%0A%09%09%7B%0D%0A%09%09
-%09
+    
 if (log.isDe
@@ -3062,39 +3062,57 @@
 g.is
-DebugEnabled())%0D%0A%09%09%09%09log.debug(
+Loggable(Level.FINE))%0D%0A%09%09%09    log.log(Level.FINE,
 %22Get

switch logging framework