package com.example.servlet;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.io.IOUtils;

public class LoggingHttpServletRequest extends HttpServletRequestWrapper {

    final byte[] buffer;

    ServletInputStream in;

    BufferedReader reader;

    public LoggingHttpServletRequest(HttpServletRequest request)
            throws IOException {
        super(request);
        InputStream in = request.getInputStream();
        try {
            buffer = IOUtils.toByteArray(in);
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    public byte[] getBuffer() throws IOException {
        return buffer;
    }

    public String getText() throws IOException {
        return new String(getBuffer(), getCharacterEncoding());
    }

    @Override
    public HttpServletRequest getRequest() {
        return (HttpServletRequest) super.getRequest();
    }

    @Override
    public void setRequest(ServletRequest request) {
        throw new UnsupportedOperationException();
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (in == null) {
            in = new Stream(buffer);
        }
        return in;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        if (reader == null) {
            reader = new BufferedReader(new InputStreamReader(
                    getInputStream(), getCharacterEncoding()));
        }
        return reader;
    }

    static class Stream extends ServletInputStream {

        final InputStream internal;

        public Stream(byte[] buffer) {
            this(new ByteArrayInputStream(buffer));
        }

        public Stream(InputStream internal) {
            this.internal = internal;
        }

        public int read() throws IOException {
            return internal.read();
        }

        @Override
        public int read(byte[] b) throws IOException {
            return internal.read(b);
        }

        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            return internal.read(b, off, len);
        }

        @Override
        public long skip(long n) throws IOException {
            return internal.skip(n);
        }

        @Override
        public int available() throws IOException {
            return internal.available();
        }

        @Override
        public boolean markSupported() {
            return internal.markSupported();
        }

        @Override
        public void mark(int readlimit) {
            internal.mark(readlimit);
        }

        @Override
        public void reset() throws IOException {
            internal.reset();
        }

        @Override
        public void close() throws IOException {
            internal.close();
        }

    }

}
