package com.example.servlet;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mule.api.transformer.TransformerException;
import org.mule.module.xml.transformer.XmlPrettyPrinter;

public class LoggingFilter implements Filter {

    static final Log log = LogFactory.getLog(LoggingFilter.class);

    XmlPrettyPrinter printer;

    public void init(FilterConfig config) throws ServletException {
        printer = new XmlPrettyPrinter();
    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        
        if (!log.isInfoEnabled()) {
            chain.doFilter(request, response);
            return;
        }
        
        doFilter((HttpServletRequest) request,
                (HttpServletResponse) response, chain);
    }

    void doFilter(HttpServletRequest request, HttpServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        
        if (log.isDebugEnabled()) {
            log.debug("Original ServletRequest: " + request);
            log.debug("Original InputStream: " + request.getInputStream());
            log.debug("Original ServletResponse: " + response);
            log.debug("Original OutputStream: " + response.getOutputStream());
        }

        StringBuilder methodAndURL = new StringBuilder()
                .append(request.getMethod())
                .append(' ')
                .append(request.getRequestURL());
        String query = request.getQueryString();
        if (query != null && query.length() > 0) {
            methodAndURL.append('?').append(query);
        }
        log.info(methodAndURL);
        log.info("Content-Type: " + request.getContentType());

        LoggingHttpServletRequest loggingRequest =
                new LoggingHttpServletRequest(request);
        LoggingHttpServletResponse loggingResponse =
                new LoggingHttpServletResponse(response);
    
        if (loggingRequest.getContentLength() > 0) {
            if (loggingRequest.getCharacterEncoding() == null) {
                log.warn("Request character encoding is null.");
                loggingRequest.setCharacterEncoding("UTF-8");
            }
            log.info("Request: " + IOUtils.LINE_SEPARATOR +
                    formatXml(loggingRequest.getText()));
        }
        
        chain.doFilter(loggingRequest, loggingResponse);
        
        log.info("Content-Type: " + response.getContentType());
        
        log.info("Response: " + IOUtils.LINE_SEPARATOR +
                formatXml(loggingResponse.getText()));
    }

    String formatXml(String text) throws ServletException {
        try {
            return (String) printer.transform(text);
        } catch (TransformerException e) {
            throw new ServletException(e);
        }
    }

    public void destroy() {
        printer = null;
    }

}
